Freeswitch CDR ODBC MySQL

Сохранение CDR в mysql и просмотр данных о звонках FreeSWITCH при помощи веб интерфейса - CDR-Viewer.

Предполагается, что сервер mysql (mariadb) установлен.

 yum install -y mysql-connector-odbc unixODBC unixODBC-devel

Проверим odbcinst.ini

# Driver from the mysql-connector-odbc package
# Setup from the unixODBC package
[MySQL]
Description     = ODBC for MySQL
Driver          = /usr/lib/libmyodbc5.so
Setup           = /usr/lib/libodbcmyS.so
Driver64        = /usr/lib64/libmyodbc5.so
Setup64         = /usr/lib64/libodbcmyS.so
FileUsage       = 1

Заполним odbc.ini

[freeswitchcdr]
Driver=MySQL
SERVER=localhost
PORT=3306
DATABASE=freeswitchcdr
USER=DB_USER
PASSWORD=DB_PASSWORD

Проверим подключение к MySQL

 echo "select 1" | isql -v freeswitchcdr
 

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

   
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> select 1
+---------------------+
| 1                   |
+---------------------+
| 1                   |
+---------------------+
SQLRowCount returns 1
1 rows fetched

Создадим БД MySQL в формате asteriskcdrdb

Создайте файл, например:

 touch freeswitchcdr.sql

И скопируйте в него структуру таблицы БД:

CREATE TABLE cdr (
   calldate datetime NOT NULL default '0000-00-00 00:00:00',
   clid varchar(80) NOT NULL default '',
   src varchar(80) NOT NULL default '',
   dst varchar(80) NOT NULL default '',
   dcontext varchar(80) NOT NULL default '',
   channel varchar(80) NOT NULL default '',
   dstchannel varchar(80) NOT NULL default '',
   lastapp varchar(80) NOT NULL default '',
   lastdata varchar(80) NOT NULL default '',
   duration int(11) NOT NULL default '0',
   billsec int(11) NOT NULL default '0',
   disposition varchar(45) NOT NULL default '',
   amaflags int(11) NOT NULL default '0',
   accountcode varchar(20) NOT NULL default '',
   uniqueid varchar(32) NOT NULL default '',
   userfield varchar(255) NOT NULL default '',
   did varchar(50) NOT NULL default '',
   recordingfile varchar(255) NOT NULL default '',
   KEY `calldate` (`calldate`),
   KEY `dst` (`dst`),
   KEY `accountcode` (`accountcode`),
   KEY `uniqueid` (`uniqueid`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

Создаем БД: freeswitchcdr

 mysqladmin create freeswitchcdr

Создаем таблицу:cdr

 mysql freeswitchcdr < freeswitchcdr.sql

Задаем права на БД с параметрами определенными в odbc.ini

 mysql> GRANT ALL PRIVILEGES ON freeswitchcdr.* TO DB_USER@localhost  IDENTIFIED BY 'DB_PASSWORD';
 flush privileges;
 \q

Расскомментируйте строку event_handlers/mod_odbc_cdr в файле исходников FS ../freeswitch/modules.conf

и выполните make && make install.

По окончании компиляции скопируйте файл odbc_cdr.conf.xml из исходников в директорию, где установлен FS.

В моем примере это /usr/local/src/freeswitch и /usr/local/freeswitch соответственно

cp /usr/local/src/freeswitch/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml /usr/local/freeswitch/conf/autoload_configs/odbc_cdr.conf.xml

И заполните файл следующим содержанием, где параметры БД (odbc-dsn), данные определенные нами в odbc.ini:

<configuration name="odbc_cdr.conf" description="ODBC CDR Configuration">
    <settings>
        <!-- <param name="odbc-dsn" value="freeswitchcdr:DB_USER:DB_PASSWORD"/> -->
        <param name="odbc-dsn" value="odbc://freeswitch" />
        <!-- global value can be "a-leg", "b-leg", "both" (default is "both") -->
        <param name="log-leg" value="both" />
        <!-- value can be "always", "never", "on-db-fail" -->
        <param name="write-csv" value="on-db-fail" />
        <!-- location to store csv copy of CDR -->
        <param name="csv-path" value="/usr/local/freeswitch/log/odbc_cdr" />
        <!-- if "csv-path-on-fail" is set, failed INSERTs will be placed here as CSV files otherwise they will be placed in "csv-path" -->
        <param name="csv-path-on-fail" value="/usr/local/freeswitch/log/odbc_cdr/failed" />
        <!-- dump SQL statement after leg ends -->
        <param name="debug-sql" value="true" />
    </settings>
    <tables>
        <!-- only a-legs will be inserted into this table -->
        <table name="cdr" log-leg="a-leg">
            <field name="calldate" chan-var-name="start_stamp" />
            <field name="clid" chan-var-name="caller_id_name" />
            <field name="src" chan-var-name="caller_id_number" />
            <field name="dst" chan-var-name="destination_number" />
            <field name="dcontext" chan-var-name="" />
            <field name="channel" chan-var-name="channel_name" />
            <field name="dstchannel" chan-var-name="bridge_channel" />
            <field name="lastapp" chan-var-name="hangup_cause" />
            <field name="lastdata" chan-var-name="sip_hangup_disposition" />
            <field name="duration" chan-var-name="duration" />
            <field name="billsec" chan-var-name="billsec" />
            <field name="disposition" chan-var-name="hangup_cause" />
            <field name="lastapp" chan-var-name="current_application" />
            <field name="amaflags" chan-var-name="amaflags" />
            <field name="uniqueid" chan-var-name="uuid" />
            <field name="recordingfile" chan-var-name="recordingfile" />
            <field name="userfield" chan-var-name="" />
        </table>
    </tables>
</configuration>

Для имени файла записи использовано имя переменной recordingfile.
В диалплане FS надо определить в контексте вызова, например:

  <action application="set" data="recordingfile=${uuid}.mp3"/>

а сама запись выполняется:

 <action application="record_session" data="$${rec_dir_custom}/${recordingfile}"/>

где, $${rec_dir_custom} глобальная переменная заданная в vars.xml:

 <X-PRE-PROCESS cmd="set" data="rec_dir_custom=/your/record_directory"/>

Загрузим модуль mod_odbc_cdr

 fs_cli
 load mod_odbc_cdr

Если в дальнейшем вы будете вносить изменения в файл odbc_cdr.conf.xml их можно применить командой:

 reload mod_odbc_cdr

reload mod_odbc_cdr

reload mod_odbc_cdr

freeswitch@internal> reload mod_odbc_cdr
+OK Reloading XML
+OK module unloaded
+OK module loaded

2016-07-21 18:58:05.585312 [CONSOLE] switch_loadable_module.c:2008 Stopping: mod_odbc_cdr
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:542 Destroying table cdr
2016-07-21 18:58:05.585312 [CONSOLE] switch_loadable_module.c:2028 mod_odbc_cdr unloaded.
2016-07-21 18:58:05.585312 [INFO] mod_enum.c:880 ENUM Reloaded
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:396 Set odbc-dsn [odbc://freeswitch]
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:405 Set debug-sql [true]
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:425 Set log-leg [both]
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:436 Set csv-path [/usr/local/freeswitch/log/odbc_cdr/]
2016-07-21 18:58:05.585312 [DEBUG] mod_odbc_cdr.c:437 Set csv-path-on-fail [/usr/local/freeswitch/log/odbc_cdr/failed/]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:113 Found table [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:117 Set table [cdr] to log A-legs only
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:128 Adding fields to table [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [calldate] (start_stamp) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [clid] (caller_id_name) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [src] (caller_id_number) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [dst] (destination_number) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [channel] (channel_name) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [dstchannel] (bridge_channel) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [lastapp] (hangup_cause) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [lastdata] (sip_hangup_disposition) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [duration] (duration) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [billsec] (billsec) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [disposition] (hangup_cause) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [lastapp] (current_application) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [amaflags] (amaflags) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [uniqueid] (uuid) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [recordingfile] (recordingfile) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] mod_odbc_cdr.c:139 Field [userfield] (branch) added to [cdr]
2016-07-21 18:58:05.585312 [INFO] switch_time.c:1415 Timezone reloaded 1781 definitions
2016-07-21 18:58:05.595283 [CONSOLE] switch_loadable_module.c:1538 Successfully Loaded [mod_odbc_cdr]

Подготовим Freeswitch CDR Viewer

Скачайте модифицированную версию с нашего сайта: freeswitch-cdr-viewer.tar.gz

 cd /var/www/html   
 
 tar zxvf freeswitch-cdr-viewer.tar.gz
  
 cd freeswitch-cdr-viewer/include

или скачайте оригинальную версию Asterisk CDR Viewer:

 git clone https://github.com/g613/asterisk-cdr-viewer.git
 
 cd asterisk-cdr-viewer/include

Отредактируем файл config.inc.php

$db_type = 'mysql';
$db_host = 'localhost';
$db_port = '3306';
$db_user = 'DB_USER';
$db_pass = 'DB_PASSWORD';
$db_name = 'freeswitchcdr';
$db_table_name = 'cdr';
$db_options = array();

Если все сделано правильно в Asterisk-CDR-Viewer будут отображаться свежие данные о вызовах:

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

Для того, чтобы работала сортировка по статусу вызова надо отредактировать файл ../asterisk-cdr-viewer/templates/form.tpl.php заменив секцию:

<td nowrap=""nowrap>
<input <?php if ( isset($_REQUEST['disposition_neg'] ) && $_REQUEST['disposition_neg'] == 'true' ) { echo 'checked="checked"'; } ?> type="checkbox" name="disposition_neg" value="true" /> not
<select name="disposition" id="disposition">
<option <?php if (empty($_REQUEST['disposition']) || $_REQUEST['disposition'] == 'all') { echo 'selected="selected"'; } ?> value="all">All Dispositions</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'ANSWERED') { echo 'selected="selected"'; } ?> value="ANSWERED">Answered</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'BUSY') { echo 'selected="selected"'; } ?> value="BUSY">Busy</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'FAILED') { echo 'selected="selected"'; } ?> value="FAILED">Failed</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'NO ANSWER') { echo 'selected="selected"'; } ?> value="NO ANSWER">No Answer</option>
</select>
</td>

на следующий код:

<td nowrap=""nowrap>
<input <?php if ( isset($_REQUEST['disposition_neg'] ) && $_REQUEST['disposition_neg'] == 'true' ) { echo 'checked="checked"'; } ?> type="checkbox" name="disposition_neg" value="true" /> not
<select name="disposition" id="disposition">
<option <?php if (empty($_REQUEST['disposition']) || $_REQUEST['disposition'] == 'all') { echo 'selected="selected"'; } ?> value="all">All Dispositions</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'NORMAL_CLEARING') { echo 'selected="selected"'; } ?> value="NORMAL_CLEARING">Answer</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'USER_BUSY') { echo 'selected="selected"'; } ?> value="USER_BUSY">Busy</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'UNALLOCATED_NUMBER') { echo 'selected="selected"'; } ?> value="UNALLOCATED_NUMBER">No Number</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'NO_ROUTE_DESTINATION') { echo 'selected="selected"'; } ?> value="NO_ROUTE_DESTINATION">No Route</option>
<option <?php if (isset($_REQUEST['disposition']) && $_REQUEST['disposition'] == 'ORIGINATOR_CANCEL') { echo 'selected="selected"'; } ?> value="ORIGINATOR_CANCEL">No Answer</option>
</select>
</td>

FreeSWITCH

  • freeswitch/db/fs_cdr_viewer.txt
  • Последние изменения: 2019/03/28