4月 022013
 

Asteriskで自宅IP-PBXを構築したので、あまり使わないがFAXも受信できるようにしてみた。
受信したデータをPDFへ変換し、メール送信するようにした。
Webで調べてみると、hylafax+iaxmodemでの構成が多いがAsterisk1.6?から、FAX機能が追加されていて比較的容易に構築できそうだった。
構築してみたのだが、受信はそこそこ満足いくできになったが、送信はSCPなりでファイルをアップして、コマンドで実行する方法にした。あまり使わないので、GUIの準備などは不要だったので。

以下のマニュアルやWikiを参考にしてやってみた。

http://voip-info.jp/index.php/Fax_for_Asterisk
http://docs.digium.com/FAX/fax_for_asterisk_admin_manual.pdf

FAX検査

AsteriskはFAXの開始音(ピーピーと5秒くらいなるやつ)を検知できるみたいで、それをsip.confに有効になるように変更します。

faxdetect=yes

faxdetectを有効にすると、ダイヤルプランでのextenのfaxへ飛ばしてくれるようになります。シンプルなダイヤルプランを設定すると、このようになります。

exten => 100,1,Answer()
exten => 100,n,WaitExten(5)
exten => fax,n,Goto(fax-rx,receive,1)
  1. 100で受信したダイヤルをAnswerで受け取ります。
  2. WaitExten(5)で、5秒間待機します。この間にFAX受信音をAsteriskが検知します。
  3. faxへ転送され、Gotoにより、fax-rxコンテキストに転送され受信処理がされます。

fax-rxコンテキストでは、さらにFAX受信で保存するファイルの指定や、PDFへ変換しメール送信するシェルなどを指定しています。

ダイヤルプラン

具体的なダイヤルプランについてですが、電話番号は1つしかないので音声とFAXの切り替え方法について、どうするのか見当してみた。一般的には、以下の2パターンあるみたいです。

  • 電話が鳴り受け取ると、FAX音の場合には人間がFAX受信ボタンを押す
  • FAX送信者が電話を掛けたときに、「FAXの方は送信し、電話の方はしばらくおまちください」とアナウンスがする

FAXはそんなに使わないということと、電話の際に必ずアナウンスを待たなければいけないのが煩わしいので、着信時にFAX音がなるパターンにした。

[general]
clearglobalvars=no
[globals]
MYPHONEN => 050********
FAXCOUNT => 0

[isp-in]
exten => ${MYPHONEN},1,NoOp(${EXTEN})
exten => ${MYPHONEN},n,NoOp("INCOME DIAL NUMBER : " ${CALLERID(number)} )
exten => ${MYPHONEN},n,Dial(DAHDI/G1&SIP/iphone&SIP/desktop,30,g)
exten => ${MYPHONEN},n,Answer()
exten => ${MYPHONEN},n,WaitExten(5)
exten => ${MYPHONEN},n,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Voicemail(2000)
exten => s-BUSY,1,Voicemail(2000)
exten => s-ANSWER,1,Hangup()
exten => _s-.,1,Goto(s-NOANSWER,1)
exten => fax,1,NoOp(**** FAX DETECTED ****)
exten => fax,n,Goto(fax-rx,receive,1)

isp-inというのは、ISP提供のIP電話サービスでここから受信した場合のコンテキスト。sip.confで設定している。MYPHONENが電話番号で、FAXCOUNTがFAX受信処理に利用するファイル名で使う変数。isp-inコンテキストの処理概要はこうなっている。

  1. NoOpで現在のextensionをコメント。通常は電話番号。
  2. NoOpで電話番号もコメントする。
  3. Dialで電話機を鳴らす。DAHDIはアナログ電話でそれ以外にクライアントPCとiPhoneにもSIPクライアントを入れているので、同時にならす。
    オプションは30秒をタイムリミットとすることと、gオプションで電話に出てFAX音を聞いて途中で切った場合でも処理を継続する。
  4. Dialで応答しなかった場合には、AnswerでAsteriskが電話に応答する
  5. WaitExtenで5秒待機。この間にFAX音をAsteriskが検知する。もしくは、上記のDialで人間が出た場合でも検知する。
  6. FAX検知しない場合(ふつうの電話)には、GotoでDIALSTATUSによる振り分けを行う
  7. s-NOANSWER, s-BUSYの場合にはVoicemailで留守電にする
  8. s-ANSWERで普通に会話が終了した場合にはHangupで終了
  9. それ以外のステータス(_s-.)の場合には、s-NOANSWERと同一(留守電)とする
  10. FAXと検知された場合にはfaxというextensionに飛ぶのでここにFAXの処理を書く。とりあえず、NoOpでコメントを書く
  11. FAXの受信処理が多かった(マニュアル抜粋でコメントばかりだけど。。)ので、Gotoでfax-rxコンテキストのreceiveのextensionに飛ばす

FAX受信処理

マニュアル抜粋のFAX受信処理のコンテキスト。ほとんど、コメントばかり。

[fax-rx]
exten => receive,1,NoOp(**** FAX RECEIVE ****)
exten => receive,n,Set(GLOBAL(FAXCOUNT)=$[${GLOBAL(FAXCOUNT)}+1])
exten => receive,n,Set(FAXCOUNT=${GLOBAL(FAXCOUNT)})
exten => receive,n,Set(FAXFILE=fax-${CALLERID(number)}-${FAXCOUNT}-rx.tif)
exten => receive,n,Set(GLOBAL(LASTFAXCALLERNUM)=${CALLERID(num)})
exten => receive,n,Set(GLOBAL(LASTFAXCALLERNAME)=${CALLERID(name)})
exten => receive,n,NoOp(**** SETTING FAXOPT ****)
exten => receive,n,Set(FAXOPT(ecm)=yes)
exten => receive,n,Set(FAXOPT(headerinfo)=MY FAXBACK RX)
exten => receive,n,Set(FAXOPT(localstationid)=1234567890)
exten => receive,n,Set(FAXOPT(maxrate)=14400)
exten => receive,n,Set(FAXOPT(minrate)=2400)
exten => receive,n,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => receive,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => receive,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => receive,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => receive,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => receive,n,NoOp(**** RECEIVING FAX : ${FAXFILE} ****)
exten => receive,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten => receive,n,System(/usr/local/bin/fax2mail.pl ${FAXFILE})
; Hangup! Print FAXOPTs
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => h,n,NoOp(FAXOPT(filename) : ${FAXOPT(filename)})
exten => h,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => h,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => h,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => h,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => h,n,NoOp(FAXOPT(pages) : ${FAXOPT(pages)})
exten => h,n,NoOp(FAXOPT(rate) : ${FAXOPT(rate)})
exten => h,n,NoOp(FAXOPT(remotestationid) : ${FAXOPT(remotestationid)})
exten => h,n,NoOp(FAXOPT(resolution) : ${FAXOPT(resolution)})
exten => h,n,NoOp(FAXOPT(status) : ${FAXOPT(status)})
exten => h,n,NoOp(FAXOPT(statusstr) : ${FAXOPT(statusstr)})
exten => h,n,NoOp(FAXOPT(error) : ${FAXOPT(error)})

Setコマンドで設定しているが、res_fax.confで設定していれば不要だと思われる。それ以外で重要な箇所を抜粋して説明する。

exten => receive,n,Set(GLOBAL(FAXCOUNT)=$[${GLOBAL(FAXCOUNT)}+1])
exten => receive,n,Set(FAXCOUNT=${GLOBAL(FAXCOUNT)})
exten => receive,n,Set(FAXFILE=fax-${CALLERID(number)}-${FAXCOUNT}-rx.tif)
exten => receive,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten => receive,n,System(/usr/local/bin/fax2mail.pl ${FAXFILE})
  1. FAXCOUNTをファイル名で利用していて、受信する度にカウントアップしている
  2. FAXFILEで電話番号-カウント-rx.tifというファイル名にしているが、Asteriskを再起動するとカウントが消えてしまうので、WikiにあるようにUNIX日付などで重複しないほうがいいかもしれない。
    Set(FAXFILE=${EPOCH}.tif)
  3. ReceiveFAXでファックスをファイルに保存する。/var/spool/asterisk/fax/ディレクトリは事前に作成し、asteriskユーザにする
  4. SystemコマンドでtiffファイルをPDFに変換してメール送信するPerlを作成した。uunicodeコマンドなどで簡単にできるが、iphoneで受信すると読めないので、MIMEエンコードするためにPerlを使ってみた。

TIFFをPDFに変換してメールするスクリプト

ここのサイトのコードを参考にして、TIFFをPDF変換するコマンドを追記などした。
PDF変換はtiff2pdfコマンドをつかって、Perlからシステムコールしている。

http://d.hatena.ne.jp/Zakk/20100604/1276410863

#!/usr/bin/perl

use Net::SMTP;
use MIME::Entity;

# Settings
our $SENDER          = 'from@foge.com';
our $RECIPIENT       = 'to@foge.com';
our $SUBJECT         = 'Fax recieved';

my $file=shift;
my $tiffile="/var/spool/asterisk/fax/$file";
my $pdffile=$tiffile;
$pdffile=~ s/.tif/.pdf/;
my $command="/usr/bin/tiff2pdf -o$pdffile $tiffile";
my $ret = system $command;
if ($ret != 0){ exit;}

# Create object
my $smtp=Net::SMTP->new('localhost',
                        HELLO=>'localhost');

# Built headers
$smtp->mail($SENDER);                 # Sender
$smtp->to  ($RECIPIENT);              # Receiver

# Built Data (Create data by MIME::Entity)
$smtp->data();
my $mime = MIME::Entity->build(
            From    =>    $SENDER   , # Sender   (data)
            To      =>    $RECIPIENT, # Receiver (data)
            Subject =>    $SUBJECT  , # Subject
            Data    => ['']);         # body

# Attached file
$mime->attach(
        Path     => $pdffile,
        Type     => 'application/pdf',
        Encoding => 'Base64'
);

$smtp->datasend($mime->stringify); # transfer strings

# Data termination and send mail
$smtp->dataend();

#Quit SMTP connection
$smtp->quit;

1;

FAX送信処理

FAX送信はSIPに対応したFAXクライアントがあればよかったのだが見つからなく、それほど送信もしないので現在は手動でSCPなりデータをUploadでAsteriskのコマンドを使って送信している。マニュアル抜粋しただけです。

[fax-tx]
exten => send,1,NoOp(**** SENDING FAX ****)
exten => send,n,Wait(6)
exten => send,n,Set(GLOBAL(FAXCOUNT)=$[ ${GLOBAL(FAXCOUNT)} + 1 ])
exten => send,n,Set(FAXCOUNT=${GLOBAL(FAXCOUNT)})
exten => send,n,Set(FAXFILE=dw-faxout.tif)
; Set FAXOPTs
exten => send,n,NoOp(**** SETTING FAXOPT ****)
exten => send,n,Set(FAXOPT(ecm)=yes)
exten => send,n,Set(FAXOPT(headerinfo)=Fax from $
{GLOBAL(LASTFAXCALLERNAME)} at ${GLOBAL(LASTFAXCALLERNUM)} was received.)
exten => send,n,Set(FAXOPT(localstationid)=1234567890)
exten => send,n,Set(FAXOPT(maxrate)=14400)
exten => send,n,Set(FAXOPT(minrate)=2400)
; Send the fax
exten => send,n,NoOp(**** SENDING FAX : ${FAXFILE} ****)
exten => send,n,SendFAX(/tmp/${FAXFILE},d)
; Hangup! Print FAXOPTs
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => h,n,NoOp(FAXOPT(filename) : ${FAXOPT(filename)})
exten => h,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => h,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => h,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => h,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => h,n,NoOp(FAXOPT(pages) : ${FAXOPT(pages)})
exten => h,n,NoOp(FAXOPT(rate) : ${FAXOPT(rate)})
exten => h,n,NoOp(FAXOPT(remotestationid) : ${FAXOPT(remotestationid)})
exten => h,n,NoOp(FAXOPT(resolution) : ${FAXOPT(resolution)})
exten => h,n,NoOp(FAXOPT(status) : ${FAXOPT(status)})
exten => h,n,NoOp(FAXOPT(statusstr) : ${FAXOPT(statusstr)})
exten => h,n,NoOp(FAXOPT(error) : ${FAXOPT(error)})

いろいろコードがあるのですが、ほとんどがコメントやFAXのオプション設定であり、FAX受信と同様に必要な箇所だけ見ると2行だけです。

[fax-tx]
exten => send,n,Set(FAXFILE=dw-faxout.tif)
exten => send,n,SendFAX(/tmp/${FAXFILE},d)

単純にファイルを送信しているだけですね。送信する場合には以下のようなコマンドを送信します。

originate SIP/050********@testphone extension send@fax-tx

testphoneは、sip.confに記載する名称で、sendfax-txは上で設定したFAX送信処理のコンテキストとExtensionの名称になります。あたり前ですが、testphoneの設定にはコンテキストの設定で電話ができる構成になってないといけません。

FAX送信テストをした場合には、もう1台の送信テスト用にAsteriskを準備でコマンドで確認しました。ある程度の動作確認ができてから、インターネットFAXサービスを利用して実際にFAX受信を確認しました。自分はPhytterというサービスからFAX送信テストをしてみました。

また、FAX送信用として以下のTIFFファイルをサンプルファイルとして活用しました。

TIFFサンプルファイル
http://www.interfax.jp/sample/index.html


Asterisk運用・開発ガイド

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>