Можно использовать сторонние сервисы, которые специализируются на этом.
Но если факсов много, то это выливается в нехилую такую копеечку. Поэтому мы будем создавать свой сервис.
Используя свой сервис, мы будем платить повременно за голосовой трафик.
Сервис будет получать запрос на отправку факса и рапортовать нам о результатах.
Использовать будем Asterisk, может он не самый производительный, но хорошо известный.
В нашей конфигурации мы будем использовать готовую сборку Elastix, т.к. она работает стабильнее, если верить Klistrod ( Битва титанов FreeSwitch vs. Asterisk — Тест производительности).
Так же плюсом является наличие Apache и php. Доставлять пакеты не придется.
В Asterisk есть несколько способов отправки факсов: голосом через G.711 и с использованием T.38.
Второй вариант предпочтительнее, т.к. вероятность доставки выше.
Так же есть 2 реализации отправки факсов:
1. Spandsp OpenSource проект
2. Digium Fax for Asterisk
Коммерческая реализация от авторов астериска, 1 конкурентная лицензия бесплатная.
Подробности установки( docs.digium.com/FAX/fax_for_asterisk_admin_manual.pdf )
Spandsp уже включена в поставку Elastix.
Логически систему можно разбить на 3 части.
1.Прием запросов
2.Ротация факсов
3.Отправка факса и рапорт о результатах.
Прием запросов на отправку.
Инициация отправки факса будет происходить посредством перемещения .call файла в папку выполения астериска.
В call файле находятся все необходимые Asteriskу параметры для отправки.
faxsend.call
Callerid:"FaxSender"<1111> Maxretries:maxRetries Waittime:300 Context:faxsend-t38 Extension:faxout RetryTime:50 Priority:1 SetVar: T38CALL=1 Set:RETURNURL={returnUrl} Set:TAGLINE=Fax from CompanyName Set:RECEIVER=Number Of Receiver Set:FAX_ID={faxId} Set:TIFF_2_SEND={faxId}.tif';
Создаем скрипт который будет принимать параметры и файл для отправки. Файл для отправки будем получать в PDF.
Параметры на которые, думаю стоит обратить внимание:
maxRetries — количество попыток дозвона.
faxid – идентификатор факса для которого будет возвращаться статус.
returnUrl – адрес по которому будет возвращаться результат отправки.
index.php
<?php define( "STATUS_SUCCESS", "success" ); define( "STATUS_ERROR", "fail" ); $pdfLocation = "//var//tmp//faxes//"; function sendStatus( $statusKind ) { header('Content-type: application/json'); exit( "{\"status\": \"" . $statusKind . "\"}" ); } $fax = $_REQUEST['fax']; $faxId = $_REQUEST['faxId']; $maxRetries = isset( $_REQUEST['maxRetries'] ) ? $_REQUEST['maxRetries'] : 0; $returnUrl = $_REQUEST['returnUrl']; $pdf = $faxId . '.pdf'; if ($fax == '' || $returnUrl == '' || $faxId == '' ) { sendStatus( STATUS_ERROR ); } if(!move_uploaded_file($_FILES['file']['tmp_name'], $pdfLocation . $pdf)) { sendStatus( STATUS_ERROR ); } $callFileBody = 'Channel:SIP/trunkname/{fax} Callerid:"FaxSender"<1111> Maxretries:{maxRetries} Waittime:300 Context:faxsend-t38 Extension:faxout RetryTime:50 Priority:1 SetVar: T38CALL=1 Set:RETURNURL={returnUrl} Set:TAGLINE=Fax from Company Set:RECEIVER={fax} Set:FAX_ID={faxId} Set:TIFF_2_SEND={faxId}.tif'; $callFileBody = str_replace("{fax}", $fax, $callFileBody); $callFileBody = str_replace("{faxId}", $faxId, $callFileBody); $callFileBody = str_replace("{maxRetries}", $maxRetries, $callFileBody); $callFileBody = str_replace("{returnUrl}", $returnUrl, $callFileBody); $callFilename = $faxId . ".call"; file_put_contents($pdfLocation . $callFilename, $callFileBody); if (!file_exists($pdfLocation . $callFilename)) { sendStatus( STATUS_ERROR ); } sendStatus( STATUS_SUCCESS ); ?>
Таким образом в указанной папке pdfLocation появляется 2 файла: .call и .pdf.
Данный скрипт можно поместить в какую-нибудь из подпапок в /var/www/html
Я создал папку faxservice.
Таким образом наш сервис доступен по адресу http://serveradress/faxservice
По-умолчанию Elastix перенаправляет все запросы http на https. Что бы не заморачиваться с сертефикатами я этот редирект отключил:
/etc/httpd/conf.d/elastix.conf
# Apache-level configuration for Elastix administration interface Timeout 300 # Default apache configuration specifies greater limits than these #MaxClients 150 #MaxRequestsPerChild 1000 # Default apache User and Group diretives MUST be commented out # in order for these to take effect. User asterisk Group asterisk <Directory "/var/www/html"> # Redirect administration interface to https #RewriteEngine off #RewriteCond %{HTTPS} off #RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} </Directory>
Просто закомментировал реврайты.
Ротация факсов
Нам необходим мониторинг этой папки на предмет появления новых заданий, и после появления заданий, передачи в очередь на отправку в Asterisk. Так же необходимо конвертация нашего pdf в tif
Данный функционал мы реализуем с помощью bash скрипта:
faxrotate
#!/bin/bash SOURCEDIR="/var/tmp/faxes/" for file in `ls $SOURCEDIR*.pdf `; do callfile="${file/pdf/call}" if [ ! -e "$callfile" ] then continue fi `gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sPAPERSIZE=letter -sOutputFile=${file/pdf/tif} $file` mv ${file/pdf/call} /var/spool/asterisk/outgoing rm $file done
Подвешиваем выполнение данного скрипта каждую минуту от имени Asterisk.
«Отработанные» файлы tif будем удалять каждую ночь, хранить их будем 2 дня (на тот случай, если количество попыток будет большим, а промежутки между ними еще больше.):
/usr/bin/find /var/tmp/faxes -name "*tif" -mtime +2 –delete
Отправка факсов Asteriskом
Осталось теперь только научить Asterisk отправлять факсы через T.38 и рапортовать нам о результатах.
Для начала необходимо «научить» Elastix работать с T.38
Для этого в sip_general_custom.conf добавляем:
t38pt_udptl=yes
А в настройках транспорта не забываем добавить
transport=udp,udptl
Примерный вид настроек транка:
[trunkname] username=username type=friend transport=udp,udptl secret=password qualify=yes nat=yes insecure=port,invite host=voip.host.com disalow=all directmedia=yes context=from-pstn canreinvite=yes allow=ulaw&alaw
Далее необходимо создать контекст, который будет вызываться из call файла
Его добавляем в
extensions_custom.conf
[faxsend-t38] exten => faxout,1,Set(STARTTIME=${SHELL(date +%s)} ) exten => faxout,n,Wait(1) exten => faxout,n,Playback(fax24,skip) exten => faxout,n,Wait(1) exten => faxout,n,NoOp(**** SENDING FAX ****) ; Set FAXOPTs exten => faxout,n,NoOp(**** SETTING FAXOPT ****) exten => faxout,n,Set(FAXFILE=${TIFF_2_SEND}) exten => faxout,n,Set(FAXOPT(ecm)=yes) exten => faxout,n,Set(FAXOPT(headerinfo)=${TAGLINE}) exten => faxout,n,Set(FAXOPT(maxrate)=14400) exten => faxout,n,Set(FAXOPT(minrate)=4800) ; Send the fax exten => faxout,n,NoOp(**** SENDING FAX : ${FAXFILE} ****) exten => faxout,n,SendFAX(/var/tmp/faxes/${FAXFILE},dfzs) ;Calculating Time of Sending exten => faxout,n,Set(ENDTIME=${SHELL(date +%s)} ) exten => faxout,n,Set(TRANSFERTIME=${MATH(${ENDTIME}-${STARTTIME},int)}) ;Actions after sending fax exten => faxout,n,Set(NORMURL=${FAXOPT(error)}) exten => faxout,n,Set(STATUSMESSAGE=${REPLACE(NORMURL, ,+)}) exten => faxout,n,Set(FAXOPTRATE=${FAXOPT(rate)}) exten => faxout,n,Hangup ;Actions if no answer or busy exten => failed,1,Set(FAXSTATUS=FAILED) exten => failed,2,Set(STATUSMESSAGE=number+no+answer+or+busy) exten => failed,3,Set(FAXOPTRATE=none) exten => h,1,NoOP(------------------- FAX to ${EXTEN} with ${FAXSTATUS} -----------------) exten => h,2,Set(CURLRESULT=${CURL(${RETURNURL}?fax=${RECEIVER}&faxId=${FAX_ID}&status=${FAXSTATUS}&message=${STATUSMESSAGE})}) exten => h,4,Set(LOGFAXOUT=${SHELL(echo "${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)} : ${FAX_ID} : ${RECEIVER} : ${FAXSTATUS} : ${STATUSMESSAGE} : ${TRANSFERTIME}s : ${FAXOPTRATE}" >> /var/log/asterisk/faxout.log)}) exten => h,3,NoOp(${RECEIVER}:${FAX_ID}:${FAXSTATUS}:${STATUSMESSAGE}:${FAXOPTRATE})
Данный контекст пытается дозвониться и отправить факс, при недозвоне он возвращает number+no+answer+or+busy.
При удачном дозвоне и попытке отправки возвращает статус и расшифровку статусного сообщения.
Эту информацию он возвращает по адресу RETURNURL из php скрипта.
Так же он пишет лог файл для дальнейших разборов полетов по каким-то спорным вопросам.
Для работы голосового приветствия необходимо записать файл в формате PCM Encoded, 16 Bits, at 8000Hz и поместить его в /var/lib/asterisk/sounds.
ссылка на оригинал статьи http://habrahabr.ru/post/183584/
Добавить комментарий