SCROLL
Среднее время на прочтение: 4 мин.

Динамические конференции на Asterisk 16 + FreePBX 14

В порядке рабочей необходимости поставилась задача по реализации динамических конференций на FreePBX. Из функционала должна быть возможность перевода активного разговора в конференцию, возможность приглашать новых участников в созданную динамическую конференцию находясь в ней, а так же возможность самостоятельному подключения к активной динамической конференции.

В интернете есть несколько примеров реализации подобного рода задачи, но я решил реализовать по своему и так как мне нужно. Итак все ниже описанные действия производились на Asterisk 16 + FreePBX 14 + phpAGI.

По-умолчанию phpAGI задействован в FreePBX и дополнительных манипуляций по его настройки не требуется. Если ниже описанные действия будут применяться к голому Asterisk, то как настроить на нем phpAGI можно прочитать из этой статьи.

Техническое задание:

  • В активном разговоре нажать *7 — создание и перевод участников разговора в конференцию.
  • В конференции нажать *7 — после гудка набрать номер кого хотим пригласить в конференцию и нажимаем #.
  • Набрать внутренний номер с префиксом *7 (прим. *71100) — если конференция с набранным номером (прим. 1100) существует, то будет присоединение к ней, в противном случае будет создана новая конференция.

Создаем скрипт /var/lib/asterisk/agi-bin/conference.php со следующим содержанием.

/var/lib/asterisk/agi-bin/conference.php
#!/usr/bin/php -q
<?php require('phpagi.php');

// ------------------------------------------------//
//      Dymanic Conf module by Jakonda© 2020       //
//      web - https://jakondo.ru                   //
// ------------------------------------------------//

// Подключение phpAGI / AGI_AsteriskManager
$agi = new AGI();
$asm = new AGI_AsteriskManager();
$asm->connect();

debug(".::: Starting scrypt (/var/lib/asterisk/agi-bin/cenference.php) :::.");

$action = $argv[1];
$confnum = $argv[2];

switch ($action) {
        case "NEW":
                newconf();
                break;
        case "ADD":
                inviteconf();
                break;
        case "MANUAL":
                manualconf();
                break;
default:

}

// Функция создания динамической конференции из активного разговора
function newconf()
{
        global $agi,$asm,$debug;

        $CL = $agi->get_variable('CHANNEL');
        $BP = $agi->get_variable('BRIDGEPEER');
        $CN = $agi->get_variable('DYNAMIC_WHO_ACTIVATED');

        $CL = $CL['data'];
        $BP = $BP['data'];
        $CN = $CN['data'];

        // Получение информации кто активировал DTMF код
        $CN = substr($CN, strpos($CN, "/") + 1, strpos($CN, "-") - 4);

        $asm->send_request('Setvar',array('Channel'=>"$CL",'Variable'=>"CONFNUM",'Value'=>"$CN"));
        $asm->send_request('Setvar',array('Channel'=>"$BP",'Variable'=>"CONFNUM",'Value'=>"$CN"));

        debug("Number [$CN] activated DTMF");
        debug("Source channel [$CL]");
        debug("Bridged channel [$BP]");

        // Проверяем если номер внутренний, то разрешаем создать динамическую
        // конференцию из текущего разговора
        if (strlen($CN) == 4) {
                debug("Allow");
        } else {
                debug("Deny");
                break;
        }

        // Перебрасываем собеседников в конференцию
        $asm->send_request('Redirect',array('Channel'=>"$CL",'ExtraChannel'=>"$BP",'Context'=>"dynamic-conference",'Exten'=>"CONF",'Priority'=>"1"));
}

// Функция добавления новых участник в динамически созданную активную конференцию
function inviteconf()
{
        global $agi,$asm,$confnum,$debug;

        // Ожидаем ввода номера для добавления в конференцию
        $result = $agi->get_data('beep', 4000, 11);
        $res = $result['result'];

        debug("Invite [$res] to dynamic conference [$confnum]");

        // Приглашаем набранный номер в конференцию
         if (strlen($res) == 4) {
                $asm->send_request('Originate',array('Channel'=>"SIP/$res",'Context'=>"dynamic-conference",'Exten'=>"CONF",'Priority'=>"1",'CallerID'=>"PBX Conference $confbum <$confnum>",'Variable'=>"CONFNUM=$confnum"));
        } else {
                $asm->send_request('Originate',array('Channel'=>"Local/$res@from-internal-additional",'Context'=>"dynamic-conference",'Exten'=>"CONF",'Priority'=>"1",'Variable'=>"CONFNUM=$confnum"));
        }
}

// Функция ручного управления. Создание динамической конференции и подключения к активной динамической конференции
function manualconf()
{
        global $agi,$asm,$debug;

        $CL = $agi->get_variable('CHANNEL');
        $EX = $agi->get_variable('EXTEN');

        $CL = $CL['data'];
        $EX = substr($EX['data'],2);

        debug("$CL");
        debug("$EX");

        $asm->send_request('Setvar',array('Channel'=>"$CL",'Variable'=>"CONFNUM",'Value'=>"$EX"));
        $asm->send_request('Redirect',array('Channel'=>"$CL",'Context'=>"dynamic-conference",'Exten'=>"CONF",'Priority'=>"1"));
}

// Функция вывода DEBUG информации в консоль
// -- полезно для отладки работы скрипта
function debug($string) {
        global $agi;
        $agi->verbose("$string");
}

?>

Выдаем права на чтение и запуск для asterisk.

chown asterisk:asterisk /var/lib/asterisk/agi-bin/conference.php
chmod 755 /var/lib/asterisk/agi-bin/conference.php

Прописываем динамическую функцию запуска скрипта, по нажатию комбинации *7 из активного разговора. В файл /etc/asterisk/features_applicationmap_custom.conf добавляем:

/etc/asterisk/features_applicationmap_custom.conf
conference=>*7,self,AGI(/var/lib/asterisk/agi-bin/conference.php,NEW)

Объявляем прописанную динамическую функцию в глобальные переменные. В файл /etc/asterisk/globals_custom.conf добавляем.

/etc/asterisk/globals_custom.conf
DYNAMIC_FEATURES=conference

Модифицируем параметры конференции, добавим возможность приглашать новых участников, по нажатию комбинации *7 в активной конференции. В файл /etc/asterisk/confbridge_custom.conf добавляем.

/etc/asterisk/confbridge_custom.conf
[dynamic_user]
type = user
talk_detection_events=yes
dsp_drop_silence=yes
announce_only_user=no

[dynamic_menu]
type = menu *7=dialplan_exec(dynamic-conference,INVITE,1)

Описываем работу динамических конференций в диалплане. В файл /etc/asterisk/extensions_custom.conf добавляем.

/etc/asterisk/extensions_custom.conf
[from-internal-custom]
include => dynamic-conference


[dynamic-conference]
; -----------------------------------------------------------------------------------------------------------------
; Динамические конференции. При активном разговоре, сотрудник может перевести разговор в конференцию, которая будет
; создана динамически(номер конференции будет присвоен такой же как и внутренний номер сотрудника). Сотрудник может
; добавить участников в созданную конференцию. Сотрудники могут подключиться к динамической конференции без 
; приглашения, а так же создать свою новую динамическую конференцию.
;
; -- Инструкция:
;  - В активном разговоре нажать *7 - создание и перевод участников разговора в конференцию
;  - В конференции нажать *7 - после гудка набрать номер кого хотим пригласить в конференцию и нажимаем #
;  - Набрать внутренний номер с префиксом *7 (прим. *71100) - если конференция с набранным номером (прим. 1100) 
;    существует, то будет присоединение к ней, в противном случае будет создана новая конференция.
; -----------------------------------------------------------------------------------------------------------------
;
exten => CONF,1,NoOp(Dynamic Conference)
exten => CONF,n,ConfBridge(${CONFNUM},,dynamic_user,dynamic_menu)

exten => INVITE,1,NoOp(Conference Invite ${CONFNUM})
exten => INVITE,n,AGI(/var/lib/asterisk/agi-bin/conference.php,ADD,${CONFNUM})

exten => _*7XXXX,1,NoOp(Create/Connect Dynamic Conference)
exten => _*7XXXX,n,AGI(/var/lib/asterisk/agi-bin/conference.php,MANUAL)
Номерной план само собой может отличаться от моего (4-х значного), поэтом строку _*7XXXX адаптируйте под свой номерной план.

Перечитываем диалплан и можно проверять работу динамических конференций.

asterisk -rx 'dialplan reload'

Обсуждение

4 комментариев
  • А как можно запустить это скрипт на FreePBX 17 asterisk 21 ну и конечно же PJsip

  • Добрый день!
    Не удается запустить скрипт на голом астериск.
    Получаю ошибку:
    AGI Tx >> agi_request: /var/lib/asterisk/agi-bin/conference1.php
    AGI Tx >> agi_channel: PJSIP/111001-00000002
    AGI Tx >> agi_language: ru
    AGI Tx >> agi_type: PJSIP
    AGI Tx >> agi_uniqueid: 1658495905.2
    AGI Tx >> agi_version: 16.2.1~dfsg-2ubuntu1
    AGI Tx >> agi_callerid: 111001
    AGI Tx >> agi_calleridname: 111001
    AGI Tx >> agi_callingpres: 0
    AGI Tx >> agi_callingani2: 0
    AGI Tx >> agi_callington: 0
    AGI Tx >> agi_callingtns: 0
    AGI Tx >> agi_dnid: *7000
    AGI Tx >> agi_rdnis: unknown
    AGI Tx >> agi_context: from-internal
    AGI Tx >> agi_extension: *7000
    AGI Tx >> agi_priority: 2
    AGI Tx >> agi_enhanced: 0.0
    AGI Tx >> agi_accountcode:
    AGI Tx >> agi_threadid: 140293074446080
    AGI Tx >> agi_arg_1: MANUAL
    AGI Tx >>
    — AGI Script /var/lib/asterisk/agi-bin/conference1.php completed, returning 0

    в чем может быть проблема?

    • Это ответ на комментарий root

      У вас используется PJSIP, а на момент написания статьи я использовал ChanSIP.