Quantcast
Channel: IP АТС Asterisk
Viewing all 1135 articles
Browse latest View live

VoIP-GSM шлюз USB HUAWEI E1550

$
0
0

VoIP-GSM шлюз USB HUAWEI E1550

Использование USB 3G модема в качестве медиа шлюза для голосовой связи из VoIPв GSM сеть и обратно. Голосовой модуль по умолчанию активирован только в модемах МТС.
Рекомендованное ядро Linux 2.6.33+
Asterisk 1.6.+
USB 2.0

Заведомо рабочие прошивки (firmware - не путать с dashboard):
МТС 11.608.12.00.143
11.608.14.15.311

Нерабочая firmware:
Мегафон 11.608.12.10.209 -при активированном голосе из под винды звонит, из под Linux - нет.

Активировать голосовую функцию можно программой DC-UNLOCKERза 4 кредита - 4 евро.

набор утилит для активации голоса

Установка asterisk из исходников

# wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-1.6.2-current.tar.gz
# tar zxvf asterisk-1.6.2-current.tar.gz
# cd asterisk-1.6.2-current.tar.gz
# apt-get install g++ libncurses-dev libxml2-dev subversion
# ./configure
# make install
# make config
# make samples

Установка модуля канала chan_datacard для Huawei

Файл datacard.confиз ~/chan_datacard/etcкопируем в каталог /etc/asterisk

# svn co http://www.makhutov.org/svn/chan_datacard/trunk/ chan_datacard
# cd ~/chan_datacard/
# ./configure
# make install
# cp ~/chan_datacard/etc/datacard.conf /etc/asterisk
usb modeswitch (не обязательно)

задание прав и пользователя устройства (Huawei E1550)

Предположим, по умолчанию так:

# ls -al /dev | grep ttyS
crw-rw----   1 root     dialout    4,  64 Сен 23 15:14 ttyUSB0
crw-rw----   1 root     dialout    4,  65 Сен 23 15:14 ttyUSB1
crw-rw----   1 root     dialout    4,  66 Сен 23 15:14 ttyUSB2

А Asterisk запущен из под одноименного пользователя

в консоли увидим:

chan_dongle.c: unable to open /dev/ttyUSB1: Permission denied

создадим правило udev

 nano /etc/udev/rules.d/e173.rules
 
 KERNEL=="ttyUSB[012]", OWNER="asterisk", GROUP="asterisk", MODE="0660"
 # /sbin/start_udev  
 # ls =la /dev | grep ttyUSB

crw-rw--   1 asterisk asterisk   4,  64 Сен 23 15:25 ttyUSB0
crw-rw--   1 asterisk asterisk   4,  65 Сен 23 15:25 ttyUSB1
crw-rw--   1 asterisk asterisk   4,  66 Сен 23 15:25 ttyUSB2

Настройка модулей

Канальный модуль Huawei настраивается в datacard.conf.

[datacard0]
audio=/dev/ttyUSB1   ; tty for audio connection
data=/dev/ttyUSB2   ; tty for AT commands

context=datacard-incoming       ; context for incoming calls
group=1                         ; calling group

rxgain=3                        ; increase the incoming volume
txgain=3                        ; increase the outgoint volume



[datacard1]
context=datacard-incoming	; context for incoming calls
audio=/dev/ttyUSB4		; tty port for audio connection
data=/dev/ttyUSB5		; tty port for AT commands
group=2				; calling group
rxgain=3			; increase the incoming volume
txgain=3			; increase the outgoint volume
autodeletesms=yes		; auto delete incoming sms
resetdatacard=yes		; reset datacard during initialization
u2diag=0			; set U2DIAG parameter (0 = disable everything except modem function)
usecallingpres=yes		; use the caller ID presentation or not
callingpres=allowed_passed_screen ; set caller ID presentation

Проверим состояние модема из командной строки Asterisk (CLI).
Перегрузить asterisk можно командой core restart now,
а если система рабочая и идут вызовы, то core restart gracefully.
Запущенные модули каналов просмотрим командой module show like chan_

asterisk*CLI> datacard show devices
ID           Group State      RSSI Mode Submode Provider Name  Model      Firmware          IMEI             IMSI       Number        
datacard1    2     Free       13   3    3       MTS RUS        E1550      11.608.12.00.143  352......        25....... Unknown       
datacard0    1     Free       15   3    3       TELE2          E1550      11.608.14.15.311  359......        25....... Unknown 

Для входящих вызовов, sms и ussd запросов настроим extensions.conf:

[datacard-incoming]
exten => sms,1,Verbose(Incoming SMS from ${CALLERID(num)} ${SMS})
exten => sms,n,System(echo '${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${DATACARD} - ${CALLERID(num)}: ${SMS}' >> /var/log/asterisk/sms.txt)
exten => sms,n,Hangup()

exten => ussd,1,Verbose(Incoming USSD: ${USSD})
exten => ussd,n,System(echo '${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${DATACARD}: ${USSD}' >> /var/log/asterisk/ussd.txt)
exten => ussd,n,Hangup()

exten => s,1,Dial(SIP/100,,)
exten => s,n,Hangup()

Для исходящей связи

exten => _X.,1,Dial(Datacard/g1/${EXTEN})
или
exten => _X.,1,Dial(Datacard/datacard0/${EXTEN})

Отключение функций CD-ROM и card reader

Отключим ненужные функции.

# minicom -s

            +-----[configuration]------+
            | Filenames and paths      |
            | File transfer protocols  |
            | Serial port setup        |
            | Modem and dialing        |
            | Screen and keyboard      |
            | Save setup as dfl        |
            | Save setup as..          |
            | Exit                     |
            | Exit from Minicom        |
            +--------------------------+
Выбираем Serial port setup и жмем ENTER. Жмем 'А' Редактируем порт:
    +-----------------------------------------------------------------------+
    | A -    Serial Device      : /dev/ttyUSB0                              |
    | B - Lockfile Location     : /var/lock                                 |
    | C -   Callin Program      :                                           |
    | D -  Callout Program      :                                           |
    | E -    Bps/Par/Bits       : 115200 8N1                                |
    | F - Hardware Flow Control : Yes                                       |
    | G - Software Flow Control : No                                        |
    |                                                                       |
    |    Change which setting?                                              |
    +-----------------------------------------------------------------------+
            | Screen and keyboard      |
            | Save setup as dfl        |
            | Save setup as..          |
            | Exit                     |
            | Exit from Minicom        |
            +--------------------------
Жмем ENTER 2 раза и выбираем Exit.

После подключения вводим команду:AT^U2DIAG=0

Welcome to minicom 2.4

OPTIONS: I18n                                                                
Compiled on Jan 25 2010, 06:49:09.                                           
Port /dev/ttyUSB0                                                            
                                                                             
Press CTRL-A Z for help on special keys                                      
                                                                             
AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0                                             
OK
AT^U2DIAG=0
OK                                                                           
Выходим Ctrl-A Q

AT^U2DIAG=0 (девайс в режиме только модем)
AT^U2DIAG=1 (девайс в режиме модем + CD-ROM)
AT^U2DIAG=255 (девайс в режиме модем + CD-ROM + Card Reader)
AT^U2DIAG=256 (девайс в режиме модем + Card Reader)
AT^CARDLOCK=«NCK-code» (разблокировка модема)
Ещё команды:

Команды AT, USB модемов HUAWEI

How To


FreeSWITCH: mod_shout error

$
0
0

FreeSWITCH: mod_shout error

При компиляции с модулем mod_shout, возникает ошибка:

make[4]: Entering directory /usr/src/freeswitch/src/mod/formats/mod_shout'
Makefile:803: *** You must install libmpg123-dev to build mod_shout. Stop.
make[4]: Leaving directory/usr/src/freeswitch/src/mod/formats/mod_shout'
make[3]: *** [mod_shout-all] Error 1
make[3]: Leaving directory /usr/src/freeswitch/src/mod'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory/usr/src/freeswitch/src'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/usr/src/freeswitch'
make: *** [all] Error 2

несмотря на то, что libmpg123-develустановлен.

Укажите путь к директории pkgconfig

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/lib64/pkgconfig

./configure

making all mod_shout

Asterisk:Лог очереди (queue) в mysql

$
0
0

Asterisk:Лог очереди (queue) в mysql

создайте таблицу в БД asterisk.

CREATE TABLE IF NOT EXISTS `queue_log` (
`time` varchar(32) DEFAULT NULL,
`callid` char(64) DEFAULT NULL,
`queuename` char(64) DEFAULT NULL,
`agent` char(64) DEFAULT NULL,
`event` char(32) DEFAULT NULL,
`data` char(64) DEFAULT NULL,
`data1` char(64) DEFAULT NULL,
`data2` char(64) DEFAULT NULL,
`data3` char(64) DEFAULT NULL,
`data4` char(64) DEFAULT NULL,
`data5` char(64) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
в файле /etc/asterisk/logger.conf выключите лог в файл:
 queue_log_to_file = no

в файле /etc/asterisk/asterisk.conf

 [options]
 queue_adaptive_realtime = yes

в файле /etc/asterisk/extconfig.conf

 queue_log => odbc,asterisk,queue_log

где asterisk ваше db конфиг в /etc/asterisk/res_odbc.conf

[asterisk]
enabled => yes
dsn => asterisk
username => dbuser
password => dbpass
pre-connect => yes

Настройка Asterisk

$
0
0

Настройка Asterisk

Документация по настройке Asterisk на русском языке.
Диалплан, SIPи DAHDIканалы, очереди, конференции, CDRи др.

Asterisk Настройка - Диалплан, Контексты, Екстеншены

Для понимания Asterisk очень важен - план набора (диалплан). Диалплан направляет каждый звонок от его источника, с помощью различных приложений, в пункт назначения. Все вызовы, будь-то голосовая почта, конференция, меню автосекретаря или вызов телефона, определяются логикой и концепцией диалплана. Русская документация мануал по dialplan Asterisk

* Asterisk Dialplan - extensions.conf

* Использование переменных в плане набора Asterisk

Команды или по другому приложения (applications) диалплана Asterisk

Функции диалплана Астериск

Asterisk Dialplan functions

Функции Asterisk используются в диалплане. Это не командыдиалпланаи не могут быть использованы прямо. Функции возвращают значение для дальнейшего использования в логике диалплана.

NAT

Конфигурационные файлы Asterisk

Большинство настроек Asterisk контролируются с помощью конфигурационных файлов, расположеных в директории /etc/asterisk. Синтаксис конфигурационных файлов был разработан для упрощенного взаимодействия с ПО (например FreePBX) или же редактирования вручную.

Каналы SIP, IAX2, DAHDI и H.323 и др.

Каналы в asterisk - это внешние или внутренние соединения, по которым производиться доставка вызовов в АТС Asterisk. Каналом может быть соединение с обычным телефонным аппаратом или с обычной телефонной линией, или он может быть виртуальным (логическим) каналом для совершения вызовов (как, например, совершение телефонных вызовов через Интернет). Сервер Asterisk не делает различий между классами каналов «FXO» и «FXS» (это значит, что он не делает различий между телефонными линиями и телефонными аппаратами). Каждый совершаемый или принимаемый вызов производиться через какой-либо определенный канал.

Шифрование в Asterisk

Очереди и Агенты Asterisk

В Asterisk поддерживается несколько очередей вызовов. Их определения находятся в файле Настройка очереди в Asterisk - queues.conf, имена очередей вызовов используются в качестве аргумента команды Queue в файле конфигурации плана набора extensions.conf. Агенты, которые обрабатывают вызовы, поступающие в очередь, описываются в файле /etc/asterisk/agents.conf.

Конференции

Asterisk позволяет организовать телеконференции с неограниченным числом пользователей.

Коды Asterisk - Абонентские функции и их свойства - feartures.conf

В файле features.conf назначаются пользовательские коды абонентских функций Asterisk и опции абонентских функций, такие как:
Переадресация вызова(transfer), перехват вызова (pickup), запись по требованию (record on demand), таймауты между набора и переадресации (digit timeout), паркинг (park) и др.

CDR

Детализированный отчет о звонках (CDR) backend для сохранения данных о входящих, исходящих и внутренних вызовах Asterisk. Полное описание на русском языке CDR, MySQL, ODBC etc.

logger

CLI - интерфейс командной строки Asterisk.

Командная строка является мощным инструментом для мониторинга и управления работой Asterisk PBX

Asterisk AMI

Asterisk manager Interface - интерфейс управления.

Asterisk ARI

FreePBX Call Recordings + Asternic CDR Stats 1.5.1

$
0
0

FreePBX Call Recordings + Asternic CDR Stats 1.5.1

Данная модификация включает отображение записей разговоров FreePBX
в модуле Asterisk CDR StatsСкачать asternic_cdr-1.5.1.tgz исправленный Скачать asternic_cdr-1.5.1.tgz исправленный

код модификации

Замените файл:

/var/www/html/admin/modules/asternic_cdr/functions.inc.phpмодуля Asternic.

на файл именем с модифицированным кодом:

[root@localhost asternic_cdr]# ls -la | grep fu
-rw-r--r--  1 asterisk asterisk 16431 Feb 13 16:17 functions.inc.php
-rw-r--r--  1 asterisk asterisk 16163 Feb 13 16:16 functions.inc.php.bk

<?php

if(isset($_SERVER['PATH_INFO'])) {
    define("SELF",  substr($_SERVER['PHP_SELF'], 0, (strlen($_SERVER['PHP_SELF']) - @strlen($_SERVER['PATH_INFO']))));
} else {
    define("SELF",  $_SERVER['PHP_SELF']);
}

function asternic_cdr_get_config($engine) {
    // Executed on APPLY in FreePBX, we regenerate the fop2buttons if needed
    global $amp_conf, $db, $active_modules;


}

function asternic_cdr_query() {

    global $active_modules, $amp_conf, $db;

    $sql = "SELECT exten,privacy,label,`group`,email,channel,queuechannel,originatechannel,customastdb,spyoptions,external FROM fop2buttons";
    $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
    if(DB::IsError($results)) {
        die($results->getMessage());
    }
    foreach ($results as $result) {
        $fopprivacy[$result['exten']]   = $result['privacy'];
        $foplabel[$result['exten']]     = $result['label'];
        $fopgroup[$result['exten']]     = $result['group'];
        $fopemail[$result['exten']]     = $result['email'];
        $fopchannel[$result['exten']]   = $result['channel'];
        $fopqchannel[$result['exten']]  = $result['queuechannel'];
        $fopochannel[$result['exten']]  = $result['originatechannel'];
        $fopcustastdb[$result['exten']] = $result['customastdb'];
        $fopspyoption[$result['exten']] = $result['spyoptions'];
        $fopexternal[$result['exten']]  = $result['external'];
    }

}

function return_timestamp($date_string)
{
  list ($year,$month,$day,$hour,$min,$sec) = preg_split("/-|:| /",$date_string,6);
  $u_timestamp = mktime($hour,$min,$sec,$month,$day,$year);
  return $u_timestamp;
}

function swf_bar($values,$width,$height,$divid,$stack)
{
    global $config;

    if ($stack==1) {
        $chart = "images/barstack.swf";
    } else {
        $chart = "images/bar.swf";
    }
    $return = "<div id='$divid'>\n";
    $return.= "</div>\n";
    $values = html_entity_decode($values);
    $return.= "<script type='text/javascript'>\n";
    $return.='$(document).ready(function() {'."\n";

    $variables = split("&",$values);
    if(isset($config['no_animation'][''])) {
        $variables[] = "noanimate=1";
    }

    $return .= "var flashvars = {\n";
    $param = Array();
    foreach($variables as $deauna) {
        $pedazos = split("=",$deauna);
        $param[]="'$pedazos[0]': '$pedazos[1]'";
    }
    $texti = implode(",\n",$param);
    $return.=$texti;
    $return.=" };\n";

    $return.= "swfobject.embedSWF('$chart', '$divid', '$width', '$height', '9.0.0', '#336699', flashvars, {wmode:'transparent'});\n";
    $return.= "});</script>\n";
    echo $return;
}

function print_exports($header_pdf,$data_pdf,$width_pdf,$title_pdf,$cover_pdf) {
        global $lang;
        global $language;
        $head_serial = serialize($header_pdf);
        $data_serial = serialize($data_pdf);
        $width_serial = serialize($width_pdf);
        $title_serial = serialize($title_pdf);
        $cover_serial = serialize($cover_pdf);
        $head_serial = rawurlencode($head_serial);
        $data_serial = rawurlencode($data_serial);
        $width_serial = rawurlencode($width_serial);
        $title_serial = rawurlencode($title_serial);
        $cover_serial = rawurlencode($cover_serial);

        $complete_self = $_SERVER['REQUEST_URI'];
                //echo "<br/><form method=post action='modules/asternic_cdr/export.php'>\n";
        echo "<br/><form method='post' action='$complete_self'>\n";
        foreach($_REQUEST as $kkey=>$vval) {
                echo "<input type='hidden' name='$kkey' value='".$vval."' />\n";
        }
                echo "<input type='hidden' name='action' value='export' />\n";
                echo "<input type='hidden' name='head' value='".$head_serial."' />\n";
                echo "<input type='hidden' name='rawdata' value='".$data_serial."' />\n";
                echo "<input type='hidden' name='width' value='".$width_serial."' />\n";
                echo "<input type='hidden' name='title' value='".$title_serial."' />\n";
                echo "<input type='hidden' name='cover' value='".$cover_serial."' />\n";
                echo "<a href='javascript:void()' class='info'><input type=image name='pdf' src='images/asternic_pdf.gif' style='border:0;'><span>";
                echo _('Export to PDF');
                echo "</span></a>\n";
                echo "<a href='javascript:void()' class='info'><input type=image name='csv' src='images/asternic_excel.gif' style='border:0;'><span>";
                echo _('Export to CSV/Excel');
                echo "</span></a>\n";
                echo "</form>";
}

function seconds2minutes($segundos) {
    $horas    = intval($segundos / 3600);
    $minutos  = intval($segundos % 3600 ) / 60;
    $segundos = $segundos % 60;
    $ret = sprintf("%02d:%02d:%02d",$horas,$minutos,$segundos);

//    return "$minutos:$segundos";
    return $ret;
}

function remove_quotes($argument) {
    return substr($argument,1,-1);
}

function asternic_download($file) {
    include("download.php");
}

function asternic_getrecords( $MYVARS ) {
    global $active_modules, $amp_conf, $db;

    $channel = $MYVARS['channel'];
    $start   = $MYVARS['start'];
    $end     = $MYVARS['end'];
    $gtype    = $MYVARS['direction'];
    $condicionextra="";

    if($gtype=='outgoing') {
        $chanfield = "channel";
        $otherchanfield = "dstchannel";
    } else {
        $chanfield = "dstchannel";
        $otherchanfield = "channel";
    }

$query = "SELECT substring($chanfield,1,locate(\"-\",$chanfield,length($chanfield)-8)-1) AS chan1,";
//$query = "SELECT IF($chanfield like 'Local/%',CONCAT('SIP',RIGHT(substring(replace($chanfield,'-','/'),1,instr($chanfield,'@')-1),instr(reverse(substring(replace($chanfield,'-','/'),1,instr($chanfield,'@')-1)),'/'))),substring($chanfield,1,locate(\"-\",$chanfield,length($chanfield)-8)-1)) as chan1, ";
//$query.= "billsec,duration,duration-billsec as ringtime,src,";
//изменение
$query.= "billsec,duration,duration-billsec as ringtime,src,recordingfile,";
$query.="IF(dst='s',dcontext,dst) as dst,calldate,disposition,accountcode,userfield,uniqueid FROM asteriskcdrdb.cdr ";
$query.= "WHERE calldate >= '$start' AND calldate <= '$end' AND (duration-billsec) >=0 $condicionextra ";
$query.= "HAVING chan1 IN ('$channel') ORDER BY calldate";


$me=true;

$res = $db->query($query);

if(DB::IsError($res)) {
    die($res->getMessage());
}

$ftype = $_REQUEST['type'];
$fdisplay = $_REQUEST['display'];
$ftab = $gtype;

$cont=0;
while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) {

      if (!(substr($row['accountcode'],0,5)=='Local' && $dispo[$row['disposition']]=='BUSY' && $row[9]=='ResetCDR')) {
         $cont++;
         $disposition = $row['disposition'];

         if(!isset($detail[$row['chan1']])) {
             $detail[$row['chan1']]="";
         }

         $me = ! $me;
         if($me==true) {
             $odclass="class='odd'";
         } else {
             $odclass="";
         }
         $bill_print = seconds2minutes($row['billsec']);

         $detail[$row['chan1']].= "<tr $odclass>\n<td>$cont</td>\n";
         $detail[$row['chan1']].= "<td style='text-align: center;' >".$row['calldate']."</td>\n";
         $detail[$row['chan1']].= "<td>".$row['src']."</td><td>".$row['dst']."</td>\n";
         $detail[$row['chan1']].= "<td align=right>".$bill_print."</td>\n";
         $detail[$row['chan1']].="<td align=right>".$row['ringtime']." "._('secs')."</td>\n";
         $detail[$row['chan1']].= "<td style='text-align: center;'>";

         if($row['disposition']=="NO ANSWER" || $row['disposition']=="FAILED") {
            $detail[$row['chan1']].="<span style='color: red;'>";
         } elseif($row['disposition']=="BUSY") {
            $detail[$row['chan1']].="<span style='color: orange;'>";
         } else {
            $detail[$row['chan1']].="<span style='color: green;'>";
         }

          $detail[$row['chan1']].= $row['disposition'];
          $detail[$row['chan1']].= "</span></td>";
//изменение
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";


//изменение
//          $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";
          $detail[$row['chan1']].= "\n</tr>\n";
      }

}

echo "<table width='99%' cellpadding=3 cellspacing=3 border=0 id='table${channel}' class='sortable'>\n";
echo "<thead><tr><td bgcolor='#ddcc00'>#</td>";
echo "<td bgcolor='#ddcc00' align='center'>"._('Date')."</td>\n";
echo "<td bgcolor='#ddcc00'>"._('From')."</td>\n";
echo "<td bgcolor='#ddcc00'>"._('To')."</td>\n";
echo "<td bgcolor='#ddcc00' align='right'>"._('Billable Time')."</td>\n";
echo "<td bgcolor='#ddcc00' align='right'>"._('Ring Time')."</td>\n";
echo "<td bgcolor='#ddcc00' align='center'>"._('Disposition')."</td>\n";
echo "<td bgcolor='#ddcc00' align='center'>"._('Listen')."</td></tr></thead>\n";
echo "<tbody>".$detail[$channel]."</tbody>\n";
echo "</table>\n";


$complete_self = $_SERVER['REQUEST_URI'];
echo "<form id='downloadform' method='get' action='$complete_self'><input type=hidden name='file' id='downloadfile' value=''><input type=hidden name='action' value='download'><input type='hidden' name='type' id='dtype' value=''><input type='hidden' id='idisplay' name='display' value=''> <input type='hidden' id='itab' name='tab' value=''></form>";

}


define('FPDF_FONTPATH',dirname(__FILE__).'/lib/font/');
include_once(dirname(__FILE__) . "/lib/fpdf.php");

class PDF extends FPDF
{

function Footer()
{
    global $lang;
    global $language;
    //Go to 1.5 cm from bottom
    $this->SetY(-15);
    //Select Arial italic 8
    $this->SetFont('Arial','I',8);
    //Print centered page number
    $this->Cell(0,10,$lang["$language"]['page'].' '.$this->PageNo(),0,0,'C');
}

function Cover($cover)
{
    $this->SetFont('Arial','',15);
    $this->MultiCell(150,9,$cover);
    $this->Ln();
}

function Header()
{
    global $title;
    //Select Arial bold 15
    $this->SetFont('Arial','B',15);
    //Move to the right
    $this->Cell(85);
    //Framed title
    $this->Cell(30,10,$title,0,0,'C');
    //Line break
    $this->Ln(10);
}

function TableHeader($header,$w)
{
    $this->SetFillColor(255,0,0);
    $this->SetTextColor(255);
    $this->SetDrawColor(128,0,0);
    $this->SetLineWidth(.3);
    $this->SetFont('','B',11);

    for($i=0;$i<count($header);$i++)
        $this->Cell($w[$i],10,$header[$i],1,0,'C',1);
    $this->Ln();
}

//Colored table
function FancyTable($header,$data,$w)
{

    $this->TableHeader($header,$w);

    //Color and font restoration
    $this->SetFillColor(224,235,255);
    $this->SetTextColor(0);
    $this->SetFont('');
    //Data
    $fill=0;
    $supercont=1;
    foreach($data as $row)
    {
        $contador=0;
        foreach($row as $valor) {
            $this->Cell($w[$contador],6,$valor,'LR',0,'C',$fill);
            $contador++;
        }
        $this->Ln();
        $fill=!$fill;
        if($supercont%40 == 0) {
            $this->Cell(array_sum($w),0,'','T');
            $this->AddPage();
            $this->TableHeader($header,$w);
            $this->SetFillColor(224,235,255);
            $this->SetTextColor(0);
            $this->SetFont('');
        }
        $supercont++;
    }
    $this->Cell(array_sum($w),0,'','T');
}
}

function asternic_export_csv($header,$data) {
    header("Content-Type: application/csv-tab-delimited-table");
    header("Content-disposition: filename=table.csv");

    $linea="";
    foreach($header as $valor) {
        $linea.="\"$valor\",";
    }
    $linea=substr($linea,0,-1);

    print $linea."\r\n";

    foreach($data as $valor) {
        $linea="";
        foreach($valor as $subvalor) {
            $linea.="\"$subvalor\",";
        }
        $linea=substr($linea,0,-1);
        print $linea."\r\n";
    }
}

function asternic_export($REQ) {

    $header = unserialize(rawurldecode($REQ['head']));
    $data   = unserialize(rawurldecode($REQ['rawdata']));
    $width  = unserialize(rawurldecode($REQ['width']));
    $title  = unserialize(rawurldecode($REQ['title']));
    $cover  = unserialize(rawurldecode($REQ['cover']));

    if(isset($_REQUEST['pdf']) || isset($REQ['pdf_x'])) {
        $pdf=new PDF();
        $pdf->SetFont('Arial','',12);
        $pdf->SetAutoPageBreak(true);
        $pdf->SetLeftMargin(1);
        $pdf->SetRightMargin(1);
        $pdf->AddPage();
        if($cover<>"") {
            $pdf->Cover($cover);
        }
        $pdf->AddPage();
        $pdf->FancyTable($header,$data,$width);
        $pdf->Output("export.pdf","D");
    } else {
        asternic_export_csv($header,$data);
    }
}

//изменение
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();
}

?>

Источник, с подробными разъяснениями

FreePBX

Asterisk CLI - интерфейс командной строки

$
0
0

Asterisk CLI - интерфейс командной строки

asterisk -vvvvvv

Командная строка является мощным инструментом для мониторинга и управления работой Asterisk PBX. При запуске asterisk с флагом -r или -c, появиться следующие приглашение:

# asterisk   -vvvr
*CLI> 

Введите core show helpи нажмите enter для получения полного списка команд:

Командная строка поддерживает вывод доступных команд по неполному вводу нажатием 'Tab':

Для получения дополнительной информации о конкретной команде, вы можете ввести core show help<command>. Например:

*CLI> core show help manager
                manager reload Reload manager configurations
    manager set debug [on|off] Show, enable, disable debugging of the manager code
          manager show command Show a manager interface command
         manager show commands List manager interface commands
        manager show connected List connected manager interface users
           manager show eventq List manager interface queued events
         manager show settings Show manager global settings
            manager show users List configured manager users
             manager show user Display information on a specific manager user
*CLI> 

Вот некоторые полезные команды:

Core

  • core set verbose <0-9> - порог отображаемой информации.
  • core reload - перечитать все конфиги
  • core restart gracefullyперезагрузить Asterisk по завершению всех текущих вызовов (свободные каналы закрываются)
  • core restart now Restart перезагрузить Asterisk немедленно
  • core restart when convenientперезагрузить Asterisk если нет разговоров

SIP

  • sip show peersпоказать существующие SIPекстеншены и их статус
  • sip show peer 100 отображает информацию о конкретном SIPекстеншене
  • sip show registryотображает состояние зарегистрированных транков

PJSIP

  • pjsip set logger {on|off|host} – Enable/Disable PJSIP Logger Output
  • pjsip show aors– Show PJSIP Aors

   Aor:  <Aor..............................................>  <MaxContact>
    Contact:  <Aor/ContactUri.................................>  <Status....>  <RTT(ms)..>
 =========================================================================================

      Aor:  1000                                                 1
    Contact:  1000/sip:1000@192.168.1.32:5060;transport=UDP;rin  Avail               9.645

      Aor:  1001                                                 1
  • pjsip show aor– Show PJSIP Aor

localhost*CLI> pjsip show aor 1000

      Aor:  <Aor..............................................>  <MaxContact>
    Contact:  <Aor/ContactUri.................................>  <Status....>  <RTT(ms)..>
 =========================================================================================

      Aor:  1000                                                 1
    Contact:  1000/sip:1000@192.168.1.32:5060;transport=UDP;rin  Avail              13.017


 ParameterName        : ParameterValue
 ==========================================================================================
 authenticate_qualify : false
 contact              : sip:1000@192.168.1.32:5060;transport=UDP;rinstance=56471484e9cd2c68
 default_expiration   : 3600
 mailboxes            :
 max_contacts         : 1
 maximum_expiration   : 7200
 minimum_expiration   : 60
 outbound_proxy       :
 qualify_frequency    : 60
 remove_existing      : true
 support_path         : false

DAHDI

  • dahdi show statusсостояние портов dahdi
  • dahdi show channelsпоказать существующие каналы

Кодеки

  • core show translation recalcрасчет перекодировки кодеков
Spoiler

ещё

  • module show like mysqlотобразить загруженные модули содержащие в названии mysql
  • pri set debug {on|off} span 1 Enables PRI debugging on a span
  • rtp set debug {on|off|ip} Enable/Disable RTP debugging

Простые CLI приемы

Есть несколько трюков, которые помогут вам в интерфейсе командной строки Asterisk. Очень удобно завершение неполного ввода клавишей TAB. Если вы введете начало команды и нажмите клавишу Tab, Asterisk попытается завершить имя команды, или покажет возможные команды, которые начинаются с буквы, которые Вы ввели. Например, введите 'co', а затем нажмите клавишу Tab.

 localhost*CLI> co
 confbridge  config      core
 localhost*CLI> co

Теперь наберите 'cor', и нажмите TAB снова. На этот раз Asterisk завершит слово, т.к. 'core' является единственной командой, которая начинается с 'cor'. Этот трюк также работает с под-командами. Например, наберите 'core show' и нажмите TAB. (Возможно, вам придется дважды нажать вкладку, если вы не поставили пробел после слова 'show'.) Asterisk покажет вам все под-команды.

localhost*CLI> core show [Tab]
application     applications    calls           channel         channels
channeltype     channeltypes    codec           codecs          config
file            function        functions       hanguphandlers  help
hint            hints           image           license         profile
settings        sound           sounds          switches        sysinfo
taskprocessors  threads         translation     uptime          version
warranty
localhost*CLI> core show

Повторение предыдущих команд.

Для просмотра ранее введенных команд, нажмите стрелочку вверх, таким образом можно пролистать всю историю назад и вперед.

Run Linux Shell Commands from The Asterisk CLI

Восклицательный знак перед командой позволяет предавать команды оболочке Linux.

 localhost*CLI> !whoami
 root
 localhost*CLI>

Настройка Asterisk

FreePBX

$
0
0

FreePBX

Настройка FreePBX Asterisk GUI Документация Мануал

FreePBX это полнофункциональный веб-интерфейс для конфигурации Asterisk PBX.

Если Вы знакомы с Asterisk, то знаете, настройка ATCосуществляется при помощи конфигурационных файлов. FreePBX предлагает простой, интуитивно понятный интерфейс для настройки и управления Asterisk PBX.
FreePBX также поставляется со многими дистрибьютивами:
AsteriskNOW, FreePBX Distro, Trixbox, Elastix
Документация Мануал FreePBX Asterisk Gui

Скачать FreePBX

Документация

Общее

Уязвимости

Admin modules

Документация по административным модулям FreePBX

Applications

Документация по модулям приложений FreePBX

Connectivity

Документация по модулям входящих исходящих соединений FreePBX.

  • Inbound Routes - Наведение входящих вызовов , DID.
  • Outbound Routes - Маршрутизирует исходящие вызовы по требуемым транкам.
  • Zap Channel DIDs - Назначение DIDдля конкретных ZAP каналов.
  • Trunks - Управляет ZAP (Dahdi), SIPпротокол, IAXканалами для выхода в общую телефонную сеть, или соединения АТС.

Settings Modules

Документация по модулям глобальных настроек каналов и приложений FreePBX

UCP

Примеры

Устаревшее

FreeSWITCH CDR Viewer

$
0
0

FreeSWITCH CDR Viewer

Просмотр данных CDR FreeSWITCH при помощи веб интерфейса Asterisk-CDR-Viewer

Подготовим FreeSWITCH для работы с MySQL через ODBC

Предполагается, что сервер 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

[freeswitch]
Driver=MySQL
SERVER=localhost
PORT=3306
DATABASE=freeswitchcdr
USER=DB_USER
PASSWORD=DB_PASSWORD
Проверим подключение к MySQL

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

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

 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`)
);
Создаем БД:freeswitchcdr
 mysqladmin create freeswitchcdr
Создаем таблицу:cdr
 mysql asteriskcdrdb < freeswitchcdr.sql
Задаем права на БД с параметрами определенными в odbc.ini

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

Подготовим FreeSWITCH

Расскомментируйте строку 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>
Загрузим модуль mod_odbc_cdr
 fs_cli
 load mod_odbc_cdr

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

 reload mod_odbc_cdr
Spoiler

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

 cd /var/www/html
 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 = 'freeswitchcdrdb';
$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


Asterisk Call Center Stats

$
0
0

Asterisk Call Center Stats

Статистика очередей колл центра Asterisk PBX.
Мод основанный на Asternic Call Center Stats lite.

Ключевые изменения:
Вместо парсинга текстового лога очереди /var/log/asterisk/queueu_log в MySQL
используется нативная БД,
формируемая, непосредственно, приложением app_queue - Asterisk PBX.

Отчеты в Asterisk Call Center Stats:

Сортировка

  • Выбор данных по:
    • очередям
    • агентам
    • дате

Реалтайм

  • Состояние агентов в реальном времени.
  • Информация о очереди:
    • Свободные агенты.
    • В разговоре.
    • Количество вызовов в очереди.
  • Вызовы ожидающие в очереди.

asterisk queue stats realtime

Отвеченные вызовы

  • Отвеченные вызовы по очередям и агентам.
  • Среднее время ожидания для очередей и агентов.
  • Среднее время разговора для очередей и агентов.
  • Количество отвеченных вызовов по агентам.
  • Процент отвеченных вызовов для очередей и агентов.

asterisk queue stats answered calls

asterisk queue stats answered calls

Неотвеченные вызовы

  • Количество неотвеченных вызовов по очередям.
  • Средняя позиция в очереди при выходе.
  • Причина разъединения: повесили трубку или отключены по таймауту.

asterisk queue stats unanswered calls

Распределение вызовов

  • Распределение вызовов по дате, по часам и дням недели

asterisk queue stats distribution calls

asterisk queue stats distribution calls

Установка Asterisk Call Center Stats

Установка приложения статистики очередей колл-центра Asterisk PBX.

Укажем Asterisk сохранять лог очереди в БД

Создайте таблицу в БД asterisk.

CREATE TABLE IF NOT EXISTS `queuelog` (
`time` varchar(32) DEFAULT NULL,
`callid` char(64) DEFAULT NULL,
`queuename` char(64) DEFAULT NULL,
`agent` char(64) DEFAULT NULL,
`event` char(32) DEFAULT NULL,
`data` char(64) DEFAULT NULL,
`data1` char(64) DEFAULT NULL,
`data2` char(64) DEFAULT NULL,
`data3` char(64) DEFAULT NULL,
`data4` char(64) DEFAULT NULL,
`data5` char(64) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

в файле /etc/asterisk/logger.confвыключите лог в файл:

 queue_log_to_file = no

в файле /etc/asterisk/asterisk.conf

 [options]
 queue_adaptive_realtime = yes

в файле /etc/asterisk/extconfig.conf

 queue_log => odbc,asterisk,queuelog

где asterisk ваше db конфиг, например в /etc/asterisk/res_odbc_custom.conf

[asterisk]
enabled => yes
dsn => asterisk
username => dbuser
password => dbpass
pre-connect => yes

Примените конфигурацию

 asterisk -rx 'core reload'

Установка и настройка Asterisk Call Center Stats

Скачайте приложение в директорию веб сервера (в примере /var/www/html):

 wget http://asterisk-pbx.ru/downloads/cdr/asterisk-queue-stats.tar.gz

Распакуйте:

 cd /var/www/html
 tar zxvf asterisk-queue-stats-001.tar.gz
 cd queue-stats

Отредактируйте файл config.phpв соответствии в вашими данными, где

  • $dbname - БД в которой вы создали таблицу queuelog (в примере - asterisk)
  • $dbname - Пользователь ДБ
  • $dbpass - Пароль БД (см. /etc/asterisk/res_odbc.conf или /etc/asterisk/res_odbc_custom.conf)

// Credentials for MYSQL database
$dbhost = 'localhost';
$dbname = 'asterisk';
$dbuser = 'root';
$dbpass = '';

// Credentials for AMI (for the realtime tab to work)
// See /etc/asterisk/manager.conf

$manager_host   = "127.0.0.1";
$manager_user   = "admin";
$manager_secret = "amp111";

Задайте права на директорию queue-stats:

 chown -R asterisk. /var/www/html/queue-stats
 

Откройте статистику в вашем любимом веб браузере:

http://ip.add.res.s/queue-stats
Spoiler

Настроим Asterisk, FreeSWITCH, OpenSIPs.

$
0
0

Настроим Asterisk, FreeSWITCH, OpenSIPs.

Интегратор облачных систем телефонных коммуникаций.

Реализуем сложные ТЗ.

Удаленно, в любой точке мира.

Установка IP АТС на открытом программном обеспечении включает в себя следующие этапы:

  1. Разработка технического задания с учетом требований заказчика и возможностей IP АТС.
  2. Подготовка договора на установку и настройку и, если требуется, поставку оборудования.
  3. Подготовка счета на оплату с учетом технического задания, согласование сроков и порядка оплаты.
  4. Удаленная установка IP АТС в любой точке мира.
  5. Установка IP АТС с выездом на объект (Санкт Петербург).
  6. Предварительная настройка оборудования в нашем сервисном центре.
  7. Сдача проекта. Проверка работоспособности всех компонентов и алгоритмов работы IP АТС.
  8. Обучение для дальнейшей эксплуатации IP АТС сотрудниками заказчика.
  9. Бесплатная техническая поддержка в течении месяца с момента запуска в эксплуатацию.

Мы находимся в Санкт-Петербурге, но работаем по всему миру!

Решения

VoIPАТС

  • Неограниченное количество VoIPабонентов и транков.
  • Запись разговоров и детализированный отчет о звонках.
  • Факс на e-mail.
  • Русскоязычный интерфейс.
  • CTI - Интеграция со сторонними приложениями.

Колл Центр

Дополнительно

  • Аудит и обслуживание уже установленных систем Asterisk, FreeSWITCH и др.
  • Написание кастомизированного диаплана под любые нужды.
  • Интеграция с устаревшими TDMАТС (Avaya, NEC, Nortel, Samsung, Panasonic, LG).
  • Аудит и настройки безопасности VoIPсистем.
  • Биллинг. Многопользовательские системы.
  • SIP proxy, SBC.

Напишите нам!

Свяжитесь с нами для получения подробной информации!
Офисная АТС

Only edit this fieldset if “Функционал” is set to “Офисная АТС”.

Колл Центр

Only edit this fieldset if “Функционал” is set to “Колл Центр”.

Кастомные решения

Only edit this fieldset if “Функционал” is set to “Все сложно”.

function 'QUEUE_MEMBER_COUNT'

function 'QUEUE_MEMBER_PENALTY'

function 'REALTIME_STORE'

$
0
0

function 'REALTIME_STORE'

Функция Asterisk: Запись множества полей в реалтайм хранилище.

Description

Эта функция запишет новый набор значений в хранилище RealTime. Если движок RT обеспечивает уникальный идентификатор записи, хранящейся, REALTIME_STORE (…) = .. создает переменную с именем канала ${RTSTOREID}, которая содержит значение уникального идентификатора. В настоящее время, максимум 30 пар 'поле/значение' поддерживается.

Синтаксис

REALTIME_STORE(family,field1,fieldN[,…],field30=val1,val2,valN[,…],val30)

Пример:

  Set(REALTIME_STORE(hints,exten,channels)=${ARG2},${ARG1})

Смотри также:

Функции Asterisk

function 'REALTIME'

$
0
0

function 'REALTIME'

Функция Asterisk: Получить/Записать значение в реалтайм хранилище.

Описание

Данная функция читает или записывает значение из/в Реалтайм хранилище.

Конструкция REALTIME(….)читает имена/значения, а REALTIME(….)=записывает новые значения.
При чтении, функция возвращает текстовую строку с разделителями. Имя и значениеразделяются символом указанным в <delim1>,
а сами пары Имя/значениеразделяются символом <delim2>. такие дела…

Если совпадений не найдено, возвращается NULL. При записи, всегда возвращается NULL.

Синтаксис

REALTIME(family,fieldmatch[,matchvalue[,delim1|field[,delim2]]])

Аргументы

  • delim1|field - Используйте <delim1> вместе <delim2> для чтения, а <field> без <delim2> для записи.

Если выполняется чтение, а <delim1> не задан, по умолчанию назначается ','.

  • delim2 - Параметр только для чтения, если не задан, по умолчанию '='.

Пример

Рассмотрим использование функции REALTIME() на простом примере реализации HOT DESK.
Абонент может занять любое рабочее место и назначить свой номер для приема звонков (hot desking).

В таблице hintsреалтайм хранилища сохраняется соответствие exten > channels.

  • exten - номер набираемый для вызова абонента.
  • channels - SIPпир вызываемый системой при наборе номера exten.

+-------+------------+
| exten | channels   |
+-------+------------+
| 6666  | 0000000009 |
| 7105  | 0000000001 |
+-------+------------+
Контекст ext-loginобрабатывает запрос абонента на регистрацию номера, кодом 0000ХХХХ, где ХХХХ номер абонента:
  • Set(hintdb=${EXTEN:4}) - сохраняем номер в переменную, предварительно отрезав 0000.
  • GoSub(sub-setsip,s,1(${CALLERID(NUM)},${hintdb})) - отправим вызов в контекст sub-setsip, с аргументами:
    • CALLERID(num) - это будет параметр channels
    • hintdb - это номер exten, который надо сопоставить с channels.

[ext-login]
exten => _0000XXXX,1,PlayBack(beep)
    same => n,Set(hintdb=${EXTEN:4})
    same => n,Verbose(${CALLERID(NUM)});
    same => n,GoSub(sub-setsip,s,1(${CALLERID(NUM)},${hintdb}))
В контексте sub-setsipсначала проверим есть ли запись о channels, т.е. аппарате с которого происходит запрос в таблице.
Если есть, отправим вызов на приоритет update, если нет, на приоритет new.
  • Set(_VCHAN=${CUT(REALTIME(hints,channels,${ARG1},:,:),:,4)})
  • GotoIf($[«${VCHAN}» = «${ARG1}»]?update:new)

в случае если запись для данного устройства уже существует, в приоритете updateзапишем новый номер в строку где channels = CALLERID(num)

  • Set(REALTIME(hints,channels,${ARG1},exten)=${ARG2})

если же строк совпадающих с CALLERID(num) устройства нет, а приоритете newсоздадим новую запись, при помощи функции REALTIME_STORE:

  • Set(REALTIME_STORE(hints,exten,channels)=${ARG2},${ARG1})

[sub-setsip]
exten => s,1,Verbose(***channels=${ARG1}***exten=${ARG2})
     same => n,Set(_VCHAN=${CUT(REALTIME(hints,channels,${ARG1},:,:),:,4)})
     same => n,GotoIf($["${VCHAN}" = "${ARG1}"]?update:new)
     
     same => n(update),Verbose(***UPDATE***)
     same => n,Set(REALTIME(hints,channels,${ARG1},exten)=${ARG2})
     same => n,SayDigits(${ARG2})
     same => n,PlayBack(ru/agent-loginok)
     same => n,hangup
     same => n(new),Verbose(***NEW***)
     same => n,Set(REALTIME_STORE(hints,exten,channels)=${ARG2},${ARG1})
     same => n,SayDigits(${ARG2})
     same => n,PlayBack(ru/agent-loginok)
     same => n,hangup

теперь при наборе номера 6666 (exten), система вызовет пир 0000000009 (channels):

[internal-call]
exten => _XXXX,1,Set(CALLERID(num)=${CUT(REALTIME(hints,channels,${CALLERID(num)},:,:),:,2)})
exten => _XXXX,n,Dial(SIP/${CUT(REALTIME(hints,exten,${EXTEN},:,:),:,4)},,treU(sub-monitor,s,1))
exten => h,1,Hangup

См. также

Функции Asterisk

function 'REALTIME_FIELD'

$
0
0

function 'REALTIME_FIELD'

Функция запроса в реальном времени. RealTime query function.

Описание
Данная функция получает одно значение -<fieldname> из БД, где <fieldmatch> содержит значение <matchvalue>.
This function retrieves a single item, <fieldname> from the RT engine, where <fieldmatch> contains the value <matchvalue>. When written to, the REALTIME_FIELD() function performs identically to the REALTIME() function.

Синтаксис
REALTIME_FIELD(family,fieldmatch,matchvalue,fieldname)

Пример
Разрешим вызовы на VIP абонента, только с определенных номеров, где

  • 4888 - привилегированный абонент
  • 4ХХХ - все отстальные

/etc/asterisk/extconfig.conf

[settings]
did_family => odbc,sql,did
cos_family => odbc,sql,cos1
Формат - family ⇒ engine,контекст в res_odbc.conf,таблица в БД

/etc/asterisk/extensions.conf

 [realtime-did]
 switch => Realtime/did1@did_family

Формат - switch ⇒ Realtime/контекст-в-БД@family

таблица did

+----+---------+-------+----------+---------+---------------------+
| id | context | exten | priority | app     | appdata             |
+----+---------+-------+----------+---------+---------------------+
|  1 | did1    | _4888 |        1 | goto    | cos1,${EXTEN},1     |
|  2 | did1    | _4XXX |        1 | dial    | PJSIP/${EXTEN},,    |
+----+---------+-------+----------+---------+---------------------+
Здесь вызовы на привилегированного абонента отправляются в контекст cos1,
на остальных разрешается набор.

Контекст cos1

[cos1]
exten => _4XXX,1,gotoif($["${CALLERID(num)}" = "${REALTIME_FIELD(cos_family,master,${EXTEN},slave)}"]?vip:all)
exten => _4XXX,n(all),verbose(DENY for ${CALLERID(num)})
exten => _4XXX,n,hangup
exten => _4XXX,n(vip),verbose(ALLOW for ${REALTIME_FIELD(cos_family,master,${EXTEN},slave)})
exten => _4XXX,n,dial(PJSIP/${EXTEN},,)

В данном контексте, проверяется по таблице cos1, может ли абонент связываться с VIP абонентом.
Если CallerID присутствует в таблице, то может.

таблица cos1

+--------+-------+
| master | slave |
+--------+-------+
| 4888   | 2667  |
| 4888   | 2668  |
+--------+-------+

см. также

Функции Asterisk


function 'AES_DECRYPT'

function 'DB'

$
0
0

function 'DB'

Функция Asterisk: читает или записывает во внутреннюю БД Asterisk (astdb.sqlite3).

ОписаниеДанная функция может читать или записывать значения в базу данных Asterisk.
В режиме чтения, функция возвращает соответствующее значение из БД в переменную DB_RESULT,
или ничего, если не существует. Чтобы убедиться, что запись существует, используйте функцию function 'DB_EXISTS'.

Синтаксис

DB(family/key)

Пример

Переадресация с внешним CallerID при помощи диалплана

Назначение

Подстановка CallerID внешнего абонента при переадресации принятого вызова на другой внутренний номер.

Описание

В данном примере, функция DBвычисляет длину CallerID вызывающего абонента и если длина более 3-х знаков,
определяет callerid, как внешний и устанавливает его для передачи в качестве CallerID внутреннего абонента, если вызов, в дальнейшем, будет переадресован.
По завершении вызова, фальшивое CALLTRACE очищается при помощи функции DB_DELETE.
(опция 'e', команды Dial, указывает выполнить расширение 'h', по завершению вызова.)

В примере:внутренние номера 1ХХ, вызовы из контекста [from-internal]

[from-internal]
exten => _1XX,1,Noop(+++set external callerid +++)
exten => _1XX,n,GoSub(sub-transfer_external_cid,${EXTEN},1(${CALLERID(num)},${EXTEN}))

[sub-transfer_external_cid]
exten => _XXX,1,Noop(~~~http://asterisk-pbx.ru~~~)
exten => _XXX,n,Set(cidint=${ARG1})
exten => _XXX,n,GotoIf($[${LEN(${DB(CALLTRACE/${ARG1})})} > 3]?external:internal)
exten => _XXX,n(external),Set(CALLERID(num)=${DB(CALLTRACE/${ARG1})})
exten => _XXX,n,Dial(SIP/${ARG2},,Tte)
exten => _XXX,n(internal),Dial(SIP/${ARG2},,Tteo)
exten => h,1,Set(DB_DELETE(CALLTRACE/${cidint})=ignored)

См. также Option app DIAL(,,o)

 

function 'CUT'

$
0
0

function 'CUT'

Функция Asterisk: разрезать строку по заданными разделителям.

Описание

Вырезать информацию из строки (переменной), ориентируясь на разделители.

Синтаксис

 CUT(varname,char-delim,range-spec)

Аргументы

  • varname - переменная для операции.
  • char-delim - Разделитель, по умолчанию '-'.
  • range-spec - Номер поля, который вам нужен со смещением начиная с 1-го, также возможно задавать диапазон полей через '-' и группировать при помощи амперса́нда - '&'.

Пример

Предположим, имеется таблица БД - devices, с данными SIPустройств.

+------+-------+------------+------------+------+-------------+---------------+
| id   | tech  | dial       | devicetype | user | description | emergency_cid |
+------+-------+------------+------------+------+-------------+---------------+
| 4889 | pjsip | PJSIP/4889 | fixed      | 4889 | sip 4889    |               |
| 4887 | sip   | SIP/4887   | fixed      | 4887 | sip 4887    |               |
| 4886 | sip   | SIP/4886   | fixed      | 4886 | sip 4886    |               |
+------+-------+------------+------------+------+-------------+---------------+
 exten => _4XXX,1,verbose(${REALTIME(devices,user,${EXTEN},:,:)})

Функция REALTIME()возвращает на строку содержащую user:4889 c двоеточием в качестве разделителя:

 Verbose("id:4889:tech:pjsip:dial:PJSIP/4889:devicetype:fixed:user:4889:description:sip 4889:")
Требуется получить технологию из поля под порядковым номером 6, в данном случае PJSIP/4889.
используем для этого функцию CUT():
 exten => _4XXX,1,verbose(${CUT(REALTIME(devices,user,${EXTEN},:,:),:,6)})

и получим требуемое значение:

 Verbose("PJSIP/4889") 

Поля 4,5 и 6:

 exten => _4XXX,1,verbose(${CUT(REALTIME(devices,user,${EXTEN},:,:),:,4-6)}) 
 Verbose("pjsip:dial:PJSIP/4889")

Поля 6 и 8:

 exten => _4XXX,1,verbose(${CUT(REALTIME(devices,user,${EXTEN},:,:),:,6&8)}) 
 Verbose("PJSIP/4889:fixed")

Функции Asterisk

function 'REALTIME_DESTROY'

$
0
0

function 'REALTIME_DESTROY'

Функция Asterisk: RealTime Destroy.

Описание

Данная функция действует наподобие REALTIME(....),
но в отличии от нее, только удаляет запись в AstDB.
Если в asterisk.confпараметр live_dangerously=no, то функция REALTIME_DESTROY,
будет выполнять только из диалплана, но не по внешним протоколам.

Синтаксис

REALTIME_DESTROY(family,fieldmatch[,matchvalue[,delim1[,delim2]]])

пример

exten => _0001,1,PlayBack(beep)
    same => n,Verbose(${CALLERID(NUM)});
    same => n,GoSub(sub-delsip,s,1(${CALLERID(NUM)}))

[sub-delsip]
exten => s,1,Verbose(${ARG1})
  same => n,Set(REALTIME_DESTROY(hints,channels,${ARG1},:,:)=ignored)
  same => n,Playback(ru/agent-loggedoff)
  same => n,hangup
См. также

Функции Asterisk

function 'REALTIME_HASH'

$
0
0

function 'REALTIME_HASH'

[Synopsis]
RealTime query function.
 
[Description]
This function retrieves a single record from the RT engine, where <fieldmatch>
contains the value <matchvalue> and formats the output suitably, such that
it can be assigned to the HASH() function.  The HASH()functionthen provides
a suitable method for retrieving each field value of the record.
 
[Syntax]
REALTIME_HASH(family,fieldmatch,matchvalue) 
[Arguments]
Not available
см. также

Функции Asterisk

Viewing all 1135 articles
Browse latest View live


Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>