Хранение записей разговоров в 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

<?php if (!defined('FREEPBX_IS_AUTH')) { die('No direct script access allowed'); } /**  * @file  * plays recording file  */ if (isset($_REQUEST['cdr_file'])) { 	include_once("crypt.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 ("<b>404 File not found! foo</b>"); 			// 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

<?php if (!defined('FREEPBX_IS_AUTH')) { die('No direct script access allowed'); }  /**  * @file  * popup window for playing recording  */ include_once("crypt.php"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">   <head>     <TITLE>CDR Viewer</TITLE> 			<style type="text/css"> 				.popup_download { 					color: #105D90;  					margin: 5px;  					font-size: 12px;  					text-align: left; 				} 			</style>     <meta http-equiv="content-type" content="text/html; charset=UTF-8">   </head>   <body> <?php  	$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("<audio controls>\n<source src=\"config.php?skip_astman=1&quietmode=1&handler=file&module=cdr&file=cdr_audio.php&cdr_file=$file\" type=\"audio/mpeg\">\n</audio>"); #--------------------- 	} ?>   </body> </html> 

Теперь можно конвертнуть имеющиеся файлы в 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-тег .

ссылка на оригинал статьи http://habrahabr.ru/post/258445/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *