avatar

FessAectan

карма
55,5
111 голосов
рейтинг
0,0
17 февраля 2014 в 06:15

Web интерфейс прослушивания записей звонков Asterisk


Поисковые системы выдают огромное количество результатов разной полезности на запрос вынесенный в заголовок.
На Хабрахабре такой статьи не нашел, а значит её нужно написать!
За основу я взял проект asterisk cdr viewer.
Перевел язык web интерфейса на великий могучий и «озвучил» его, т.е. добавил возможность прослушивать файлы записей разговоров в браузере, а так же скачивать их.
Количество полей фильтра сокращено до минимума, остались только самые необходимые.
Скриншоты, сорцы и подробное описание инсталляции уютно разместились под хабракатом.

UPDATE
внизу статьи скрины и линк на еще более красивый и кастомизированный вариант Asterisk CDR Viewer от камрада prog-it
его доработка имеет свои особенности, поробнее ниже


Скриншоты web интерфейса

Логотип и ссылка на донат разработчикам остались на своих местах.
Поля переведены все, если потребуется вывести какое-либо поле как в оригинале, просто раскомментируйте его в templates/form.tpl.php


А так выглядит результат поиска по фильтру.
Каждый разговор можно скачать, либо прослушать через flash плеер.


Готовим MySQL

CDR нашего Asterisk должны писаться в MySQL базу, о том как это настроить можно прочесть здесь например ;).
Имя файла записи разговора пишется в поле file таблицы CDR.
Добавим его:
mysql -uroot -p -e "alter table  `cdr` add column `filename` varchar(120)  after `userfield`;"  asterisk


Диалплан

Для настройки диалплана Asterisk я пользуюсь extensions.ael.
extensions.ael
globals {
    WAV=/records/wav; //Временный каталог с WAV
    MP3=/records/mp3; //Куда выгружать mp3 файлы
    RECORDING=1; // Запись, 1 - включена.
};

macro recording (calling,called) {
        if ("${RECORDING}" = "1"){
              Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called});
              Set(monopt=nice -n 19 /usr/bin/lame -b 32  --silent "${WAV}/${fname}.wav"  "${MP3}/${fname}.mp3" && rm -f "${WAV}/${fname}.wav" && chmod o+r "${MP3}/${fname}.mp3");
              Set(CDR(filename)=${fname}.mp3);
              Set(CDR(realdst)=${called});
              MixMonitor(${WAV}/${fname}.wav,b,${monopt});

       }; 
};

_XXXXXX => {
        &recording(${CALLERID(number)},${EXTEN});
        Dial(SIP/rtk/${EXTEN});
        Hangup();
        }


Глобальные переменные определяют пути к файлам, а так же позволяют включить/выключить запись разговора.
Макрос recording принимает в качестве параметров номер звонящего и номер куда происходит вызов. Если запись включена, то пишется временный wav файл, перекодируется в mp3, а в MySQL табличку CDR падает имя файла.
Имя файла состоит из uniqueid-дата_время-ОтКогоВызов-КомуВызов, например:
1392597899.17572-2014-02-17-07_44-83843ZZZХХХ-32ХХZZ.mp3 

mp3 файлы за текущий день складываются в /records/mp3/
Каждую ночь скрипт в кроне распределяет записи разговоров в соответствующие дате папки
1 0 * * * /root/sh/mvrecords.sh

#!/bin/bash
ym=`date +%Y-%m -%d "-1 day"`
ymd=`date +%Y-%m-%d"-1 day"`
mkdir -p /records/mp3/$ym/$ymd/
mv /records/mp3/*$ymd* /records/mp3/$ym/$ymd/


В папке, где размещены файлы web интерфейса, необходимо создать симлинк на папку /records/mp3/
/var/www# ls -l
total 60
-rw-r--r-- 1 fessae fessae   182 Nov 19  2011 callrates.csv
drwxr-xr-x 3 fessae fessae  4096 Sep 26  2012 contrib
-rw-r--r-- 1 fessae fessae  1986 Dec 22  2012 download.php
-rw-r--r-- 1 fessae fessae   246 Sep  6  2013 downloads.php
drwxr-xr-x 4 fessae fessae  4096 Apr 15 20:48 include
-rw-r--r-- 1 fessae fessae 30384 Dec  2 20:21 index.php
lrwxrwxrwx 1 root   root      13 Apr 15 20:48 records -> /records/mp3/
drwxr-xr-x 2 fessae fessae  4096 Feb 13  2013 style
drwxr-xr-x 3 fessae fessae  4096 Feb 18 21:07 templates


Скриншоты структуры папок.




PHP

В файле include/functions.php прописана логика вывода кнопочки «скачать файл с разговором» и flash плеера в поле «Файл».
часть include/functions.php
    $recorded_file = $row['filename'];
    $mycalldate = substr("$calldate",0,10);
    $mycalldate_ym = substr("$calldate",0,7);
    $mydate = date("Y-m-d");
    

if ($mycalldate<$mydate){
if (file_exists("records/$mycalldate_ym/$mycalldate/$recorded_file")) {
echo " <td class=\"record_col\"><a href=\"downloads.php?audio=records/$mycalldate_ym/$mycalldate/$recorded_file\" title=\"Скачать файл с разговором\"><img src=\"templates/images/sound.png\"</a>
                <object type=\"application/x-shockwave-flash\" data=\"include/player_mp3_maxi.swf\" width=\"150\" height=\"20\">
                                <param movie=include/player_mp3_maxi.swf/> 
                                <param name=FlashVars value=mp3=records/$mycalldate_ym/$mycalldate/$recorded_file />     </td>\n";
}
else {echo "    <td class=\"record_col\">запись отсутствует</td>\n"; }
}
else {
if (file_exists("records/$recorded_file")) {
echo " <td class=\"record_col\"><a href=\"downloads.php?audio=records/$recorded_file\" title=\"Скачать файл с разговором\"><img src=\"templates/images/sound.png\"</a>
                <object type=\"application/x-shockwave-flash\" data=\"include/player_mp3_maxi.swf\" width=\"150\" height=\"20\">
                                <param movie=include/player_mp3_maxi.swf/> 
                <param name=FlashVars value=mp3=records/$recorded_file />     </td>\n";
}
else {echo "    <td class=\"record_col\">запись отсутствует</td>\n";}

}
}


В этом коде определяется в какой папке нужно искать файл записи разговора.
За текущий день ищем в /records/mp3, а за предыдущие в /records/mp3/ГОД-МЕСЯЦ/ГОД-МЕСЯЦ-ДЕНЬ/
Если файл найден не был, то мы увидим «запись отсутствует» в поле «Файл».

Так же не забываем указать реквизиты подключения к MySQL в include/config.inc.php

Занавес

На этом все!
Буду рад если мой труд окажется полезен.

ps
Сорцы доступны по ссылкам 1 и 2

UPD
Если нет аккаунта на Хабре, могу помочь на форуме — sysadminz.ru/index.php?topic=6592.0
UPD 2
Обнаружился небольшой глюк, если запись по каким-либо направлениям отключена(т.е. не пишется файл и не заполняется поле filename в базе), то флеш плеер все равно отображается, как-будто файл есть.
Для исправления нужно внести изменения в таблицу CDR, для поля filename выставить значение по умолчанию:
mysql -p
mysql> alter table cdr alter filename set default 'none';
mysql> describe cdr;
+-------------+-----------------+------+-----+---------------------+----------------+
| Field       | Type            | Null | Key | Default             | Extra          |
+-------------+-----------------+------+-----+---------------------+----------------+
| id          | int(9) unsigned | NO   | PRI | NULL                | auto_increment |
| calldate    | datetime        | NO   | MUL | 0000-00-00 00:00:00 |                |
| clid        | varchar(80)     | NO   |     |                     |                |
| src         | varchar(80)     | NO   | MUL |                     |                |
| dst         | varchar(80)     | NO   | MUL |                     |                |
| dcontext    | varchar(80)     | NO   |     |                     |                |
| channel     | varchar(80)     | NO   |     |                     |                |
| dstchannel  | varchar(80)     | NO   |     |                     |                |
| lastapp     | varchar(80)     | NO   |     |                     |                |
| lastdata    | varchar(80)     | NO   |     |                     |                |
| duration    | int(11)         | NO   |     | 0                   |                |
| billsec     | int(11)         | NO   |     | 0                   |                |
| disposition | varchar(45)     | NO   |     |                     |                |
| amaflags    | int(11)         | NO   |     | 0                   |                |
| accountcode | varchar(20)     | NO   | MUL |                     |                |
| uniqueid    | varchar(32)     | NO   | MUL |                     |                |
| userfield   | varchar(255)    | NO   |     |                     |                |
| filename    | varchar(120)    | YES  |     | none                |                |
+-------------+-----------------+------+-----+---------------------+----------------+
18 rows in set (0.00 sec)

mysql> \q
Bye

UPD 3(из шапки поста)
Камрад profiton (aka prog-it) существенно допилил тему.
Скрины:
image
image
image
image

Фичи:
Основные особенности
Полностью русский интерфейс
Обновленный дизайн
Всплывающие подсказки
Корректный экспорт записей в CSV файл
Правильный подсчет стоимости звонков (плагин)
Просмотр стоимости каждого звонка (плагин)
Возможность указать нетарифицируемый интервал для правильного подсчета стоимости
Возможность указать доп. тариф. Например: Стоимость первой минуты 1 руб., далее по 10 коп. (доп. тариф)
Имя файла записи звонка хранится в базе
Возможность прослушивания записи звонка через веб-интерфейс
На номер телефона можно нажать и получить о нем информацию
Плеер для прослушивания звонка подгружается через javascript, так что ничего не тормозит
Если записи звонков архивируются, будет предложено скачать запись
Если поступил факс, его также можно скачать
Файлы для скачивания отдаются скриптом с возможностью докачки
Папка для хранения записей может находиться в любой директории вашего сервера
И еще много всего...


Линк — prog-it.github.io/Asterisk-CDR-Viewer-Mod
+14
39879
235

Комментарии (33)

+2
AndreyBerezhnoy #
Ага, вот значит как АНБ работает.
+3
Avenit #
1. А почему бы сразу не писать в папку с нужной датой? Asterisk даже сам создаст директорию если ее нет.
2. А вот перекодировку лучше перенести как раз на ночное время, так как это дико жрущая процессор задача и даже рпи среднем количестве звонков начинаются кваканья.
0
FessAectan #
1. Согласен, так действительно проще было бы.
2. Там приоритет у процесса перекодировки минимальный, при 6-7к звонков в день, на одном из объектов, справлялся
компьютер с 2-х ядерный процессором и 4Гб ОЗУ.
0
datacompboy #
Могу посоветовать писать не в MP3, для снижения нагрузки, а в обычные астерисковые wav'ы.
А проигрывать онлайн моим WavPlayer'ом.
0
FessAectan #
Благодарю, в случае необходимости обязательно воспользуюсь.
+1
utya #
Где ты был товарищ 2 года назад)
0
FessAectan #
Ждал подобного комментария =)))
+1
lostinfuture #
В чем отличие от oreka.sourceforge.net/?
0
FessAectan #
Не могу сказать, до Вашего комментария не знал о проекте.
0
lostinfuture #
Не совсем понятно каким образом оно пишет RTP. Разве Asterisk не занимается только разруливанием звонков?
0
FessAectan #
Каким образом не подскажу, но таки пишет :)
Документация — wiki.asterisk.org/wiki/display/AST/Application_MixMonitor
0
lostinfuture #
Просто в той же ореке нужно мирорить трафик с астериска и с телефонных портов/vlan на сервер ореки…
+1
zepps #
Астериск нативно пишет разговоры, ТС лишь доработал оболочку для работы с ними.
OREKA — пишет разговоры, перехватывая их RTP-сессиями, что целесообразно использовать лишь для станций, не имеющих функционала, аналогичного астеру, либо требующих за него отдельных денег.
0
maksimrussia #
FessAectan, подскажите как мне прикрутить возможность просмора транка, через который поступил входящий звонок и через который был совершен исходящий звонок вместо:


Это нужно для определения на какой номер поступил входящий звонок при наличии нескольких линий.
0
FessAectan #
На скорую руку могу предложить вот такой солюшн:
найдите в коде include/functions.inc.php функцию formatChannel и замените код на этот
function formatChannel($channel) {
        $chan_type = explode('/', $channel);
        $chan_id = explode('-',$chan_type[1]);
        echo "    <td class=\"record_col\"><abbr title=\"Channel: $channel\">$chan_type[0]/$chan_id[0]</abbr></td>\n";
}

0
maksimrussia #
Спасибо! Вечером буду тестить! )
0
g613 #
оригинальный cdr-viewer вроде по дефолту скачивать фалы позволяет и былоб неплохо с последней весией смержить.
0
FessAectan #
Весь необходимый функционал есть, не вижу смысла мерджить.
0
qmax #
Вообще, для колцентров есть более узкоспециализированные решения, с поиском, по оператору или очереди.
0
foxmuldercp #
Угу. Cisco Call Manager, например, или п/о от Indosoft, индусское поделие. в смысле, его реально индусы пишут.
0
qmax #
А что у них по ценам?
0
foxmuldercp #
Ой, это к вендорам/реселлерам, я только видел железки, местами интерфейс, но больше деталей при всё желании не могу сообщать, потому что ни цен ни особенностей не знаю
0
Celebro #
Не пробовали записывать звонки из agi-cgi? Как-то пробовал, но что-то пошло не так, файлы wav не создавались. Документацию по реализации этого так и не нашёл, и отложил в недолгий ящик. Может вы сталкивались с этим? Конкретнее сейчас описать проблему не могу, надо поднимать и воссоздавать тестируемую схему.
0
FessAectan #
Не смогу ничего подсказать по Вашему вопросу к сожалению.
0
AlexeyNikolaev #
Вот такую пользовательскую панель сделали для FreePBX twitter.com/tm1000/status/436002671615418368

image
0
FessAectan #
Красота!
0
mysticmirage #
Добавил в functions.inc.php перед if ($mycalldate<$mydate){:

$recorded_file_url = urlencode("$recorded_file");

И поменял в ссылках $recorded_file на $recorded_file_url
Сделано для того, чтобы записи с номеров/на номера, начинающиеся на «+», корректно скачивались и прослушивались.
0
bpxmsg #
Мы юзаем Aptus FonB, достаточно няшный, правда с кириллицей как то странно работает.
+1
zombic #
Предлагаю для воспроизведения файлов средствами браузера использовать тег
<audio src="URL"></audio>

Тогда не придется использовать сторонний проигрыватель. Из плюсов — воспроизведение wav-файлов (соответственно, нет необходимости конвертировать запись в mp3).

У себя сделал так:
if (file_exists("records/$pathtofile/$recorded_file")) {
echo "	<td><audio src=\"records/$pathtofile/$recorded_file\" type=\"audio/wav\" controls=\"controls\"></td>\n"; 

Выглядит это так

0
datacompboy #
не все браузеры на проигрывают wav.
0
zombic #
Ограничения, конечно, есть. Я лишь предложил удобный вариант, который мне замечательно подошел.
0
FessAectan #
Замечательное предложение!
Не проверяли — быстрее страничка грузится без flash плеера?(по идее должна грузиться быстрее)
0
zombic #
Загружается моментально.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.