[Из песочницы] Хранение записей разговоров в mp3 во FreePBX/Asterisk

Ныне FreePBX — крайне популярная обертка к Asterisk, который не менее популярен как телефонный цифровой сервер. Отдельный плюс таких систем — возможность развернуть на недорогих vds-серверах (я клиентам разворачиваю на vds стоимостью 299р/месяц, 2Гб ОЗУ, 2,8 GHZ процессор, 20Гб место на диске). Такая система запросто обслуживает 10–20 одновременных звонков, пишет аудио, позволяет внедрять телефонную часть бизнес-процесса в остальную логику (взаимодействие с crm, звонки с сайта/браузера, автоинформаторы на основе данных в субд, выяснение поисковых данных по номеру о звонящем за доли секунд, даже распознавание и синтезация речи!).Все бы хорошо, но при «обильных» обзвонах через полмесяца заканчивается место на диске. Те самые 20Гб улетают у некоторых клиентов за неделю! А хостер, к сожалению, не предоставляет fuse на тарифах OpenVZ, который крайне необходим для работы «реалтайм — сетевых файловых систем», вроде ftpfs.

Ниже изложу мой комплекс мер по борьбе с проблемой. Работать будем с каталогом /var/spool/asterisk/monitor, где лежат .wav файлы, заботливо разложенные asterisk по каталогам: год, месяц и день.Изначально я пошел не с того края — стал перебрасывать часть данных на webdav (ya.disk) и ftp. Делалось это скриптом, запускаемым раз в месяц по крону. Скрипт оставлял указанное количество месяцев на сервере, остальное переносил на удаленный ресурс.

Для yandex.disk он дополнительно паковал данные «помесячно», что требовало свободного места для создания архива. Но, тем не менее, кое-где он прижился:

#settings #for disk.yandex.ru YAUSER=login@yandex.ru YAPASSWORD=verystrongpassword

MONPATH=/var/spool/asterisk/monitor LASTMONTH=1 #сколько последних месяцев оставляем на сервере DIR=astsounds #название удаленной директории, где будем хранить архивы

#start MONTH=$(date +»%m») for YEAR in $(ls $MONPATH); do for MONTH in $(ls $MONPATH/$YEAR/); do if [ $MONTH -le $(($(date +»%m»)-$LASTMONTH)) ] || [ $YEAR -ne $(date +»%Y») ]; then tar -zcvf $MONPATH/$YEAR/$MONTH/$YEAR-$MONTH.tar.gz $MONPATH/$YEAR/$MONTH/ >/dev/null curl -T $MONPATH/$YEAR/$MONTH/$YEAR-$MONTH.tar.gz --user $YAUSER:$YAPASSWORD https://webdav.yandex.ru/$DIR/$YEAR-$MONTH.tar.gz && rm -f -r $MONPATH/$YEAR/$MONTH >/dev/null fi done #remove old YEAR dir if [ $YEAR -ne $(date +»%Y») ]; then rm -f -r $MONPATH/$YEAR fi done Когда писал подобный скрипт для ftp, решил отказаться от архивирования аудио. И доставать проще, и ссылки формировать на сторонний ресурс можно, для онлайн-прослушивания из CDR-отчета. Требует lftp-утилиту. #move audio records to XXX.ru free FTP server #settings FTPSRV=node0.XXXX.ru FTPUSER=username_ftpserver FTPPWD=passwd_ftpserver MONPATH=/var/spool/asterisk/monitor LASTMONTH=1 DIR=recordings

#log and cd ftpcommand () { lftp -u $FTPUSER,$FTPPWD -e »$1» $FTPSRV }

ftpcommand «mkdir public_http; mkdir public_http/$DIR; quit;»

MONTH=$(date +»%m») for YEAR in $(ls $MONPATH); do for MONTH in $(ls $MONPATH/$YEAR/); do if [ $MONTH -le $(($(date +»%m»)-$LASTMONTH)) ] || [ $YEAR -ne $(date +»%Y») ]; then echo «saving $YEAR/$MONTH» ftpcommand «mkdir public_http/$DIR/$YEAR; mkdir public_http/$DIR/$YEAR/$MONTH; quit;» for DAY in $(ls $MONPATH/$YEAR/$MONTH/); do ftpcommand «mkdir public_http/$DIR/$YEAR/$MONTH/$DAY; quit;» for FILE in $(ls $MONPATH/$YEAR/$MONTH/$DAY); do ftpcommand «cd /public_http/$DIR/$YEAR/$MONTH/$DAY/; put $MONPATH/$YEAR/$MONTH/$DAY/$FILE; quit;» done done rm -f -r $MONPATH/$YEAR/$MONTH fi done #remove old YEAR dir if [ $YEAR -ne $(date +»%Y») ]; then rm -f -r $MONPATH/$YEAR fi done Данный скрипт также забрасывался в месячный крон.Но кое-кому, как я уже писал, этого не хватало. Данные забивали диск за неделю. Тогда пришла мысль хранить все в mp3. По факту — выигрыш составлял от 4-х раз. Потребуется lame.

Для начала положим в /etc/asterisk такой вот скрипт mixmon_mp3.sh и дадим ему одного с asterisk хозяина: chown asterisk. mixmon_mp3.sh. Также дадим право на выполнение: chmod +x mixmon_mp3.sh.

#!/bin/sh #convert wav to mp3 asterisk recordings cdrdb=«asteriskcdrdb» cdrtable=«cdr» astdbuser=«asteriskuser» #пользователь субд для отчетов astdbuserpass=«asteriskuserpassword» #пароль пользователя субд

for i in `find /var/spool/asterisk/monitor -type f -name »$1»` do if [ -e »$i» ]; then file=`basename »$i» .wav`; dir=`dirname »$i»`; lame -h -b 192 »$i» »$dir/$file.mp3»; rm -f »$dir/$file.wav»; sleep 3 mysql --user=»$astdbuser» --password=»$astdbuserpass» --database=»$cdrdb» --execute='UPDATE '$cdrtable' SET recordingfile=»'$file'.mp3» WHERE recordingfile=»'$file'.wav»;'; fi done

Далее в вебморде FreePBX, в разделе Settings — Advanced Settings включаем Display Readonly Settings и Override Readonly Settings, после чего становится доступна настройка Post Call Recording Script в разделе Developer and Customization. Туда и прописываем строку вызова скрипта с параметром: /etc/asterisk/mixmon_mp3.sh ^{CALLFILENAME}.^{MIXMON_FORMAT} К сожалению, переменная MIXMON_DIR оказалась пустой, поэтому приходится довольствоваться именем файла и отыскивать его в каталоге monitor. Скрипт находит файл, конвертирует его в mp3, удаляет wav и правит запись в таблице cdr, где хранятся отчеты. Это нужно для нормального прослушивания и скачивания файлов в вебморде с отчетами.Также нам понадобится допилить сам модуль вебморды cdr:/var/www/html/admin/modules/cdr/cdr_audio.php

$REC_CRYPT_PASSWORD = (isset ($amp_conf['AMPPLAYKEY']) && trim ($amp_conf['AMPPLAYKEY']) != »)? trim ($amp_conf['AMPPLAYKEY']):'TheWindCriesMary'; $crypt = new Crypt (); $opath = $_REQUEST['cdr_file']; $path = $crypt→decrypt ($opath,$REC_CRYPT_PASSWORD);

// Gather relevent info about file $size = filesize ($path); $name = basename ($path); $extension = strtolower (substr (strrchr ($name,».»),1)); // This will set the Content-Type to the appropriate setting for the file $ctype =''; switch ($extension) { case «WAV»: $ctype=«audio/x-wav»; break; case «wav»: $ctype=«audio/x-wav»; break; #--------------------- case «mp3»: $ctype=«audio/mpeg»; break; #--------------------- case «ulaw»: $ctype=«audio/basic»; break; case «alaw»: $ctype=«audio/x-alaw-basic»; break; case «sln»: $ctype=«audio/x-wav»; break; case «gsm»: $ctype=«audio/x-gsm»; break; case «g729»: $ctype=«audio/x-g729»; break; default: //not downloadable // echo (»404 File not found! foo»); // TODO: what to do if none of the above work? break; }

$fp=fopen ($path, «rb»); if ($size && $ctype && $fp) { header («Pragma: public»); header («Expires: 0»); header («Cache-Control: must-revalidate, post-check=0, pre-check=0»); header («Cache-Control: public»); header («Content-Description: audio file»); header («Content-Type:» . $ctype); header («Content-Disposition: attachment; filename=» . $name); header («Content-Transfer-Encoding: binary»); #--------------------- header («Accept-Ranges: bytes»); header («Connection: close»); header («Content-Length: $size»); header («Content-Range: bytes 0-$size/$size»); header («Content-length:» . $size); #--------------------- $chunksize = 1*(1024×1024); while (! feof ($fp)) { $buffer = fread ($fp, $chunksize); echo $buffer; ob_flush (); flush (); } fclose ($fp); } }

?> cdr_play.php

/** * @file * popup window for playing recording */ include_once («crypt.php»); ?> CDR Viewer

$crypt = new Crypt ();

$REC_CRYPT_PASSWORD = (isset ($amp_conf['AMPPLAYKEY']) && trim ($amp_conf['AMPPLAYKEY']) != »)? trim ($amp_conf['AMPPLAYKEY']):'TheWindCriesMary'; $path = $crypt→decrypt ($_REQUEST['recordingpath'],$REC_CRYPT_PASSWORD); $file = urlencode ($crypt→encrypt ($path,$REC_CRYPT_PASSWORD)); if (isset ($file)) { #--------------------- echo (»»); #--------------------- } ?> Теперь можно конвертнуть имеющиеся файлы в mp3 и положить на всякий случай этот скрипт в дневной крон: #!/bin/sh #convert wav to mp3 asterisk recordings cdrdb=«asteriskcdrdb» cdrtable=«cdr» astdbuser=«asteriskuser» astdbuserpass=«asteriskuserpassword» for i in `find /var/spool/asterisk/monitor -type f -name »*.wav»` do if [ -e »$i» ]; then file=`basename »$i» .wav`; dir=`dirname »$i»`; lame -h -b 192 »$i» »$dir/$file.mp3»; rm -f »$dir/$file.wav»; mysql --user=»$astdbuser» --password=»$astdbuserpass» --database=»$cdrdb» --execute='UPDATE '$cdrtable' SET recordingfile=»'$file'.mp3» WHERE recordingfile=»'$file'.wav»;'; fi done Процесс небыстрый, лучше запускать на ночь. Теперь у нас намного экономнее расходуется место, прослушивание отчетов не требует QuickTime и файл нам проигрывает браузер через HTML5-тег .

© Habrahabr.ru