среда, 10 сентября 2014 г.

FreePBX + Asternic CDR Reports + Recordings

FreePBX, Asternic CDR Reports и записи звонков

ВВЕДЕНИЕ
Классический CDR Reports, "идущий в комплекте" с FreePBX умеет делать отчёты с проигрыванием аудиозаписи, если она велась, но не умеет разграничивать доступы по Extension`ам (Extension Range, который задаётся при создании новой учётной записи админа).
Модуль Asternic CDR Reports учитывает это, но не выводит аудиофайл.
Исправим это.


Информация о звонках в Asterisk`е хранится в mysql базе данных asteriskcdrdb, таблица cdr.

_______
$resultscdr = $dbcdr->getAll($query, DB_FETCHMODE_ASSOC);
...
foreach($resultscdr as $row)
...
        if ($row['recordingfile']) {
            $rec_parts = explode('-',$row['recordingfile']);
            $fyear = substr($rec_parts[3],0,4);
            $fmonth = substr($rec_parts[3],4,2);
            $fday = substr($rec_parts[3],6,2);
            $monitor_base = $amp_conf['MIXMON_DIR'] ? $amp_conf['MIXMON_DIR'] : $amp_conf['ASTSPOOLDIR'] . '/monitor';
            $recordingfile = "$monitor_base/$fyear/$fmonth/$fday/" . $row['recordingfile'];
            if (!file_exists($recordingfile)) {
                $recordingfile = '';
            }
        } else {
            $recordingfile = '';
        }
...
_______

Из вышеприведённого кода файла page.cdr.php модуля обычного CDR Reports ясно, что всё, что нам нужно - это прочитать значение ячейки recordingfile (там хранится строка "файл.wav") и добавить к нему полный путь к файлу, выдираемый, кстати, из самого же имени файла
_______
            $fyear = substr($rec_parts[3],0,4);
            $fmonth = substr($rec_parts[3],4,2);
            $fday = substr($rec_parts[3],6,2);
            $monitor_base = $amp_conf['MIXMON_DIR'] ? $amp_conf['MIXMON_DIR'] : $amp_conf['ASTSPOOLDIR'] . '/monitor';
            $recordingfile = "$monitor_base/$fyear/$fmonth/$fday/" . $row['recordingfile'];
_______
$amp_conf - глобальный массив, из которого берутся пути к записям. Поэтому, если менялся путь по-умолчанию, всё ок.

ПРАКТИКА
В файле functions.inc.php модуля Asternic ищем строку
_______
$query.= "billsec,duration,duration-billsec as ringtime,src,";
_______
добавляем к запросу recordingfile
_______
$query.= "billsec,duration,duration-billsec as ringtime,src,recordingfile,";
 _______

Затем вместо
_______
          $detail[$row['chan1']].= "\n<td>";

          $uni = $row['uniqueid'];
          $uni = str_replace(".","",$uni);

             if($row['userfield']<>"") {
              $detail[$row['chan1']].="<a href=\"javascript:void(0);\" onclick='javascript:playVmail(\"".$row['userfield']."\",\"play".$uni."\");'>";
              $detail[$row['chan1']].="<div class='playicon' title='Play' id='play".$uni."'  style='float:left;'>";
              $detail[$row['chan1']].="<img src='images/blank.gif' alt='pixel' height='16' width='16' border='0'>";
              $detail[$row['chan1']].="</div></a>";
              $detail[$row['chan1']].="<a href=\"javascript:void(0); return false;\" onclick='javascript:downloadVmail(\"".$row['userfield']."\",\"play".$uni."\",\"$ftype\",\"$fdisplay\",\"$ftab\"); return false;'>";
              $detail[$row['chan1']].="<div class='downicon' title='Download' id='dload".$uni."'  style='float:left;'>";
              $detail[$row['chan1']].="<img src='images/blank.gif' alt='pixel' height='16' width='16' border='0'>";
              $detail[$row['chan1']].="</div></a>";
          } else {
              $detail[$row['chan1']].= "&nbsp;";
          }
          $detail[$row['chan1']].= "</td>\n";
_______

ставим
_______
          if ($row['recordingfile']) {
            $rec_parts = explode('-',$row['recordingfile']);
            $fyear = substr($rec_parts[3],0,4);
            $fmonth = substr($rec_parts[3],4,2);
            $fday = substr($rec_parts[3],6,2);
            $monitor_base = $amp_conf['MIXMON_DIR'] ? $amp_conf['MIXMON_DIR'] : $amp_conf['ASTSPOOLDIR'] . '/monitor';
            $recordingfile = "$monitor_base/$fyear/$fmonth/$fday/" . $row['recordingfile'];
            if (!file_exists($recordingfile)) {
                $recordingfile = '';
                $detail[$row['chan1']].= "\n<td>";
            }
            else {
            $detail[$row['chan1']].= "\n<td style='text-align: center;' title=\"$row[recordingfile]\"><a href=\"".$PHP_SELF."?getRec=".base64_encode($recordingfile)."\" target=\"_blank\"><img src=\"images/asternic_playicon.png\" alt=\"Call recording\" /></a>";
            }
        } else {
            $recordingfile = '';
            $detail[$row['chan1']].= "\n<td>";
        }
          $detail[$row['chan1']].= "</td>\n";
_______

По-умолчанию в ячейке Listen в Asternic выводится запись голосовой почты, но нас-то интересует запись звонка, поэтому меняем содержимое всей ячейки.

В конце файла добавляем ещё функцию, отдающую файл двоичными данными (т.е. никакой apache не имеет доступа к каталогу записи, а отдаётся всё через php) и проверку на наличие переменной getRec, в случае наличия которой получаем файл.
_______
function recordfile_uri($path) {
    $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 "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("Content-length: " . $size);
    $chunksize = 1*(1024*1024);
    while (!feof($fp)) {
        $buffer = fread($fp, $chunksize);
        echo $buffer;
        ob_flush();
        flush();
    }
    fclose($fp);
  }
}
if(isset($_GET['getRec'])){
    recordfile_uri(base64_decode($_GET['getRec']));
    die();
}
_______ 

7 комментариев:

  1. привет!
    на какой версии freepbx у тебя завелось?
    на 2.8 (elastix) получаю сообщение "DB Error: no such field".
    на чистом freepbx 2.11 при нажатии на кнопку "play" просто перекидывает на страницу "FreePBX System Status".

    если не трудно, выложи конфиг-файл целиком

    ОтветитьУдалить
    Ответы
    1. В статье была ошибка, в одном месте denis_getRec, в другом просто getRec. Должно быть одинаково, иначе как раз нажатие на кнопку "play" не туда ведёт.
      Поправил. Исправь у себя - и всё заработает :)

      С Elastix не работал, но если там asterisk 1.8 и он ведёт свои cdr-логи в mysql, то, по идее, должы быть те же поля.

      Удалить
    2. Действительно, все заработало! Очень круто, спасибо!

      Кстати, давеча вышел FreePBX Stable-6.12.65, там появилась возможность случать записи онлайн (без QT плеера, на чистом html5) - есть 2 симпатичные кнопки.

      Если есть желание приделать эти кнопки к asternic.... Короче, ждем-с новых статей:)

      Удалить
    3. Добрый день!

      Прошу помочь, сделал все как описано, но записи в столбце Listen не отображаются. записи на самом сервере имеются.

      Удалить
    4. Здесь версия статьи более читабельная http://habrahabr.ru/post/244321/

      Какие версии FreePBX и Астериска?

      Вариант а) Другой путь до аудиофайла
      Вариант б) В mysql нет данных в recordingfile

      Удалить
  2. Спасибо, был другой путь, Теперь вопрос как мне изменить имя файла записи и вытащить записи по uniqeuid, почему именно так потому что стоит система биллинга a2billing которая складывает аудиозаписи c названием uniqueid.

    ОтветитьУдалить
  3. FreePBX 2.9.0.15 и Asterisk (Ver. 1.8.10.1) получаю сообщение "DB Error: no such field"
    Включил запись всех звонков в менеджере соединений, напротив звонка появились кнопки Play и скачать, но ни воспроизведение ни скачивание тоже не работают. Можете подсказать куда смотреть дальше?

    ОтветитьУдалить