All pages
Powered by GitBook
1 of 20

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Сценарии и кейсы

Программное создание сотрудников

Пример использования REST API для генерации сотрудников

В релизе 2023.2 реализовано API для быстрого создания большого количества сотрудников, в процессе тестирования мы описали алгоритм генерации нового сотрудников в ChatGPT и провели нагрузочное тестирование по созданию 700 произвольных учетных записей на разных языках. На загрузку ушло около 1 минуты, тест прошел успешно.

Для выполнения этой задачи был написан запрос к ChatGPT следущего содержания.

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

Для получения структуры данных необходимо выполнить следующий GET запрос с пустым ID

http://127.0.0.1:8081/pbxcore/api/extensions/getRecord?id=

В ответ мы получим JSON примерно такого содержания:

{"jsonapi":{"version":"1.0"},
    "result":true,
    "data":
        {
            "type":"SIP",
            "show_in_phonebook":"1",
            "is_general_user_number":"1",
            "public_access":"0",
            "number":"275",
            "user_id":"",
            "user_avatar":"",
            "user_username":"",
            "user_email":"",
            "mobile_uniqid":"EXTERNAL-7870338E",
            "mobile_number":"",
            "mobile_dialstring":"",
            "sip_uniqid":"SIP-PHONE-5A230111",
            "sip_secret":"Nk9oOFI2ZXdDMEU9",
            "sip_type":"peer",
            "sip_qualify":"1",
            "sip_qualifyfreq":60,
            "sip_enableRecording":"1",
            "sip_dtmfmode":"auto",
            "sip_transport":" ",
            "sip_networkfilterid":"none",
            "sip_manualattributes":"",
            "fwd_ringlength":45,
            "fwd_forwarding":"",
            "fwd_forwardingonbusy":"",
            "fwd_forwardingonunavailable":""
        },
    "messages":[],
    "function":"getRecord",
    "processor":"MikoPBX\\PBXCoreREST\\Lib\\Extensions\\GetRecord::main",
    "pid":42448,
    "meta":{
        "timestamp":"2023-09-06T08:51:51+03:00",
        "hash":"a16f973985cb3d0cbe75abb2c10a7c39b2203a87"
        }
}

Если параметр result в ответе будет равен true, то возьмем данные для создания нового пользователя 
из параметра data и выполним POST запрос на адрес http://127.0.0.1:8081/pbxcore/api/extensions/saveRecord,
используя полученный после модификации массив полей формы отправив его в формате x-www-form-urlencoded.

Скрипт должен быть написан на Python без использования NodeJS и позволять создать 100 различных сотрудников.
В поле user_username вписываем имя и фамилию произвольного человека, чтобы использовались национальные алфавиты.
В поле user_email произвольный адрес электронной почты.
В поле mobile_number произвольные мобильные номера телефонов, только цифры, без дублей.
В поле fwd_forwarding, fwd_forwardingonbusy заполнить значениями mobile_number.

При создании сотрудника, вывести user_username, user_email и number в консоль и сообщить о результате.

Если в результате запроса к saveRecord или getRecord мы получили result равный false, 
то также в консоль вывести параметр messages из полученного ответа. 
Если в результате ответа мы получили ошибку другого типа, или ответ невозможно разобрать,
то вывести в консоль полный текст полученный от API сервера.

В результате был сгенерирован Python скрипт, который позволил выполнить этот тест.

CreateRandomExtensions.py
import requests
import random
from faker import Faker

def generate_random_mobile():
    return ''.join(random.choice("1234567890") for _ in range(11))

def main():
    faker_ru = Faker('ru_RU')
    faker_en = Faker('en_US')
    faker_zh = Faker('zh_CN')
    faker_ja = Faker('ja_JP')

    for number in range(1, 699):
        # Получение шаблона данных для нового сотрудника
        get_response = requests.get("http://127.0.0.1:8081/pbxcore/api/extensions/getRecord?id=")

        if get_response.json().get('result', False) == False:
            print(f"getRecord error: {get_response.json().get('messages', 'Unknown error')}")
            continue

        data = get_response.json().get('data', {})

        # Генерация произвольных данных
        locale = random.choice(['ru_RU', 'en_US', 'zh_CN', 'ja_JP'])
        faker = locals()[f"faker_{locale.split('_')[0].lower()}"]
        data['user_username'] = faker.name()
        data['user_email'] = faker.email()
        data['mobile_number'] = generate_random_mobile()
        data['fwd_forwarding'] = data['mobile_number']
        data['fwd_forwardingonbusy'] = data['mobile_number']

        # Создание нового сотрудника
        post_response = requests.post("http://127.0.0.1:8081/pbxcore/api/extensions/saveRecord", data=data, headers={'Content-Type': 'application/x-www-form-urlencoded'})

        if post_response.json().get('result', False):
            print(f"Created user {number} -> Username: {data['user_username']}, Email: {data['user_email']}, Mobile: {data['mobile_number']}")
        else:
            print(f"saveRecord error for user {number}: {post_response.json().get('messages', 'Unknown error')}")

        if post_response.status_code != 200 or not isinstance(post_response.json(), dict):
            print(f"Unknown error: {post_response.text}")

if __name__ == "__main__":
    main()

Для запуска подобного скрипта, сохраним его в папке /tmp внутри MikoPBX. Т.к. скрипт имеет несколько зависимостей, добавим их через установщик пакетов pip3 и запустим скрипт для генерации.

cd /tmp
python -m venv venv --without-pip
source venv/bin/activate
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
pip3 install faker requests
python CreateRandomExtensions.py

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

MikoPBX процесс нагрузочного тестирования интерфейса и REST API
MikoPBX результат работы скрипта генерации произольного набора сотрудников

Важно отметить, т.к. система read-only, то установку Python библиотек необходимо выполнять посое каждой перезагрузки, а папка /tmp будет очищена. Разработку и доработку скрипта необходимо вести во внешней системе.

При выполнении REST API запросов из внешних адресов, необоходимо выполнить авторизацию административным логином и паролем или создать пользователя с правами на указанные действия в модуле управления правами сотрудников и авторизовываться им.

При выполнении запросов, как в этом примере, с адреса 127.0.0.1 авторизация не требуется.

Уведомление в телеграмм о пропущенных

В данной статье будет рассмотрено два способа реализации уведомления о пропущеных вызовах в Telegram

Пример на базе Dialplan

Полезная статья по работе с Telegram-ботом средствами curl.

  1. Перейдите в раздел "Кастомизация системных файлов":

Раздел "Кастомизация системных файлов"
  1. Перейдите в раздел редактирования файла "extensions.conf". Установите режим "Добавлять в конец файла" и вставьте следующий контекст:

[add-trim-prefix-clid-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(start check blacklist)
	same => n,Set(CHANNEL(hangup_handler_push)=hangup-ext-queues,h,1);
	same => n,Return()

[hangup-ext-queues]
exten => h,1,ExecIf($["${M_DIALSTATUS}" = "ANSWER"]?return)
    same => n,Set(TOKEN=5118292900:AAEWCOAXkay5fXb8AJptZmDyqkNk8QbP200)
    same => n,Set(CHAT_ID=939950800)
    same => n,Set(URL=https://api.telegram.org/bot${TOKEN}/sendMessage)
    same => n,Set(TEXT=MISSED CALL from: ${CALLERID(name)}, did: ${FROM_DID}, callid: ${CHANNEL(callid)})
    same => n,SHELL(curl -s -X POST '${URL}' -d chat_id='${CHAT_ID}' -d text='${TEXT}')
    same => n,Set(MISSED=${SHELL(curl -s -X POST '${URL}' -d chat_id='${CHAT_ID}' -d text='${TEXT}')})
    same => n,return

В данном конктексте замените:

  • TOKEN - токен вашего бота в телеграмм.

  • CHAT_ID - идентификатор чата, куда отправлять текстовое сообщение.

Сохраните изменения.

Редактирование файла "extensions.conf"
  1. Перейдите в раздел редактирования файла "modules.conf". Установите режим "Добавлять в конец файла" и вставьте следующий контекст:

load => func_shell.so

Сохраните изменения.

Редактирование файла "modules.conf"

Средставми curl можно выполнить запрос к любому сайту. К примеру можно отправить уведомление в slack:

same => n,Set(MISSED=${SHELL(curl -X POST --data-urlencode "payload={\"channel\": \"#cannel_name\", \"username\": \"bot_name\", \"text\": \"Пропущенный вызов от ${CALLERID(name)} по внешней линии: ${FROM_DID} в ${STRFTIME(${EPOCH},,%H:%M:%S %d-%m-%Y)}\", \"icon_emoji\": \":sos:\"}" https://hooks.slack.com/services/T76G7L0/B01R/VMPQUeAN)}) 

Пример на базе PHP-AGI

  1. Перейдите в раздел "Приложения диалпланов". Создайте новое приложение, нажав на "Добавить новое":

Добавление нового приложения диалплана
  1. Укажите следующие параметры для диалплана:

  • Название - произвольное

  • Номер для вызова приложения - произвольный номер

  • Тип кода - "PHP-AGI скрипт"

Параметры диалплана
  1. Перейдите во вкладку "Программный код". Вставьте следующий PHP-AGI скрипт:

<?php
require_once 'Globals.php';
use \GuzzleHttp\Client;

const API_KEY = '';
const CHAT_ID = '';

$agi = new MikoPBX\Core\Asterisk\AGI();

$name = $agi->get_variable('CALLERID(name)', true);
$num  = $agi->get_variable('CALLERID(num)', true);
$did  = $agi->get_variable('$FROM_DID', true);
$id   = $agi->get_variable('CHANNEL(linkedid)', true);
$date = date('Y.d.m H:i:s', str_replace('mikopbx-', '', $id));

$TEXT = "Пропущенный вызов: $name, did: $did, callid: $num, id: $id, date: $date";
$apiURL = 'https://api.telegram.org/bot' . API_KEY . '/';
$client = new Client([
    'base_uri' => $apiURL,
    'timeout' => 1,
    'http_errors' => false,
]);
try {
    $client->post( 'sendMessage', ['query' => ['chat_id' => CHAT_ID, 'text' => $TEXT]] );
}catch (Throwable $e){
}

В данном конктексте замените:

  • API_KEY - токен вашего бота в телеграмм.

  • CHAT_ID - идентификатор чата, куда отправлять текстовое сообщение.

Текст уведомления можно исправить в переменной «$TEXT».

  1. После сохранения скрипта из адресной строки браузера скопируйте идентификатор скрипта, который имеет вид: «DIALPLAN-APP-1B2B846E»:

Идентификатор приложения диалплана
  1. Перейдите в раздел "Кастомизация системных файлов":

Раздел "Кастомизация системных файлов"
  1. Перейдите в раздел редактирования файла "extensions.conf". Установите режим "Добавлять в конец файла" и вставьте следующий контекст:

[add-trim-prefix-clid-custom]
exten => _.X!,1,Set(CHANNEL(hangup_handler_push)=hangup-ext-queues,h,1);
	same => n,return
[hangup-ext-queues]
exten => h,1,ExecIf($["${M_DIALSTATUS}" = "ANSWER"]?return)
    same => n,AGI(DIALPLAN-APP-1B2B846E.php)
    same => n,return

Замените "DIALPLAN-APP-1B2B846E" на Ваш идентификатор провайдера.

Сохраните изменения.

Редактирование файла "extensions.conf"

Отключить переадресацию на мобильный для внутренних звонков

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

  1. Перейдите в раздел «Система» -> «Кастомизация системных файлов»

  1. Выберите для редактирования файл «/etc/asterisk/extensions.conf»

  1. Выберите режим «Добавлять в конец файла»

  1. Добавьте во второе поле текст

[internal-users-custom]
; Только для внутренних отключаем переадресацию. 
exten => _X!,1,ExecIf($[ "${FROM_DID}x" == "x" ]?Set(__QUEUE_SRC_CHAN=${CHANNEL}))
	same => n,return
  1. Сохраните изменения

Отправка входящего факса на email

  1. Добавьте новое приложение dialplan (см. )

  1. Назначьте внутренний номер, к примеру 2200110

  1. Вставьте следующий код во вкладку "Программный код"

В коде приложения укажите свой email вместо адреса «[email protected]».

  1. Перейдите в раздел "Кастомизация системных файлов"

  1. Откройте для редактирования файл "extensions.conf"

  1. Добавьте следующий код в конец файла:

    «2200100» замените на номер своего приложения

В коде, «SIP-1687941868» замените на ID своего провайдера. Подсмотреть его значение можно в карточке провайдера, в адресной строке браузера

  1. Откройте для редактирования файл "modules.conf"

  1. Вставьте в конец файла код:

  1. В карточке провайдера, в расширенных настройках, в дополнительных параметрах укажите

Регистрация нескольких учетных записей от одного провайдера

Инструкция по подключению учетной записи провайдера доступна по .

Многие операторы связи не могут предложить несколько SIP-номеров в одном транке (в качестве одной учетной записи провайдера) и выдают для каждого номера свои регистрационные данные. Например, используя провайдера Zadarma, для подключения номера телефона +7(495)-229-30-42 следует использовать логин 847706, пароль XXXXXX, а при подключении номера телефона +7 (499) 638-25-84 следует использовать логин 847900, пароль YYYYYY. При этом хост будет для двух учетных записей одинаковым: sip.zadarma.com. Задача: необходимо для каждого номера задать определенную входящую маршрутизацию, например при звонке на номер +7(495)-229-30-42 вызов должен направляться на отдел продаж (очередь вызовов), а при звонке на номер +7 (499) 638-25-84 вызов должен направляться на IVR-меню. Потенциальная проблема: проблема заключается в том, что все входящие звонки пойдут через первого провайдера Zadarma, который определен в учетных записях MikoPBX. Вызовы через второго провайдера MikoPBX никогда не пройдут.

Решение

  1. В разделе Маршрутизация → Провайдеры телефонии создайте две учетные записи провайдера от одного поставщика услуг связи. В нашем примере это Zadarma. Укажите верный логин, пароль и хост.

  1. В дополнительных параметрах укажите:

  1. В разделе Маршрутизация → Входящие маршруты задайте правило входящих звонков для каждого провайдера. В поле Дополнительный номер вставьте логин от учетной записи провайдера. В поле Провайдер выберите Любой.

Инструкции по настройке входящей маршрутизации доступны по .

Как реализовать функцию супервизора

Создание диалплана

  1. Перейдите в раздел «Модули» - «Приложения диалпланов». Создайте новый диалплан.

  1. Укажите название «Подслушивание». Укажите «номер для вызова приложения», тут будем использовать шаблон «911XXX» - XXX означает все трехзначные числовые номера. В поле «тип кода» укажите «Диалплан Asterisk»

Шаблоны

Дальнейший функционал вы можете выбрать из трех вариантов:

1. Подслушать разговор

Появляется возможность подслушать чужой разговор, так что ни оператор, ни клиент ничего не заподозрят

Во вкладке ''Программный код'' вставьте следующий код:

ChanSpy(SIP/${EXTEN:3},qw) - обратите внимание, в качестве EXTEN будет передан номер приложения. Если вы набираете 911101, то будет набран внутренний номер 101. Отсекаются первые три цифры.

Если вы измените длину шаблона, то следует скорректировать эту строку.

При использовании PJSIP команда будет иметь вид ChanSpy(PJSIP/${EXTEN:3},qw)

2. Вмешаться в разговор

Во вкладке ''Программный код'' вставьте следующий код:

Отличия только в параметрах для ChanSpy

3. ''Шепнуть'' коллеге

Во вкладке ''Программный код'' вставьте следующий код:

Отличия только в параметрах для ChanSpy

Отключение "нерабочего времени" для VIP номеров

  1. Подключите провайдеров, зарегистрированных на одном хосте, как описано в .

  2. Перейдите в раздел Система → Кастомизация системных файлов.

  1. Откройте для редактирования конфигурационный файл extensions.conf.

  1. Установите режим «Добавлять в конец файла». В черное окно добавьте следующий фрагмент кода:

Вместо номеров X9522140000 и X9629771111 укажите номера телефонов клиентов, в том виде, как они отображаются в истории звонков.

<?php
require_once 'Globals.php';

use \MikoPBX\Core\Asterisk\AGI;
use MikoPBX\Core\System\Notifications;
use MikoPBX\Core\System\{MikoPBXConfig};

$agi     = new AGI();
$faxFile = "/tmp/" .$agi->get_variable("CDR(linkedid)", true).'.tiff';
$caller  = $agi->get_variable("CALLERID(num)", true);
$agi->exec("ReceiveFax", "{$faxFile},d"); 
$result  = $agi->get_variable("FAXOPT(status)", true);

if($result === 'SUCCESS' && file_exists($faxFile)){
    $notify = new Notifications();
    $notify->sendMail('[email protected]', 'Fax msg from '.$caller, 'Incoming fax <br><br>', $faxFile);
    unlink($faxFile);
}
sleep(1);
[SIP-1687941868-incoming](+)
exten => fax,1,Goto(internal,2200100,1)
load => res_fax.so
load => res_fax_spandsp.so
[endpoint]
fax_detect=yes
fax_detect_timeout=30
Приложения диалпланов
Новое приложение диалпланов
Внутренний номер приложения
Раздел "Кастомизация системных файлов"
Конфигурационный файл "extensions.conf"
Код для extensions.conf
ID провайдера
Конфигурационный файл "Modules.conf"
Код для modules.conf
Код в дополнительных параметрах провайдера
[endpoint]
context=public-direct-dial
ссылке
ссылке
Настройки провайдера
Дополнительные настройки провайдера
Новое правило обработки входящих вызовов
1,Answer()
n,ChanSpy(${CHANNEL(channeltype)}/${EXTEN:3},qw)
n(hangup),Hangup();
1,Answer()
n,ChanSpy(${CHANNEL(channeltype)}/${EXTEN:3},qBx)
n(hangup),Hangup();
1,Answer()
n,ChanSpy(${CHANNEL(channeltype)}/${EXTEN:3},wvq(4)x)
n(hangup),Hangup();
Новое приложение диалплана
Шаблон параметров для диалплана
Первый вариант реализации
Второй вариант реализации
Третий вариант реализации
[add-trim-prefix-clid-custom]
; Игнор нерабочего времени VIP номера для двойного тарифа по работам:
exten => _.X!/_X9522140000,1,Set(IGNORE_TIME=1)
    same => n,return
exten => _.X!/_X9629771111,1,Set(IGNORE_TIME=1)
    same => n,return
инструкции
Раздел кастомизации системных файлов
Конфигурационный файл "extensions.conf"
Код для extensions.conf

Конвертация истории звонков FreePBX -> MikoPBX

PT1C_cdr это таблица с историей звонков от панели телефонии версии 1 в FreePBX.

Действия в FreePBX

  1. Перейдем в рабочий каталог FreePBX

    mkdir -p /usr/src/miko-mysql-to-sqlite;
    cd /usr/src/miko-mysql-to-sqlite
  2. Скачаем скрипт конвертации таблицы MySQL в Sqlite3. Скачать, если его нет.

    curl '' -o 'mysql2sqlite.sh'
  3. Запускаем скрипт конвертации:

     ./mysql2sqlite.sh -ufreepbxuser -p123 asteriskcdrdb PT1C_cdr | grep -v 'CREATE INDEX' | sqlite3 ./master.db

Действия в MikoPBX

Архив со скриптами доступен по ссылке

  1. Файл master.db, полученный на предыдущем этапе необходимо перенести на MIKOPBX в каталог «/storage/usbdisk1/mikopbx/freepbx-dmp»

  2. Перейти в рабочий каталог MIKOPBX:

    mkdir -p /storage/usbdisk1/mikopbx/freepbx-dmp;
    cd /storage/usbdisk1/mikopbx/freepbx-dmp;
  3. Подготовка списка файлов к загрузке в качестве даты следует указать свою «2020-02-07»:

    sqlite3 master.db 'SELECT strftime("%Y/%m/%d/", calldate) || recordingfile FROM PT1C_cdr WHERE recordingfile<>"" AND calldate > "2020-02-07"' > file-for-download.txt
  4. Загрузка записей разговоров и конвертация в MP3

    curl '' -o ./download-and-convert.sh
    sh ./download-and-convert.sh file-for-download.txt 10.70.10.6:443
  5. Выполним резервное копирование базы данных истории звонков:

    cp /storage/usbdisk1/mikopbx/astlogs/asterisk/cdr.db /storage/usbdisk1/mikopbx/astlogs/asterisk/cdr.db.dmp
  6. Скопируем базу данных истории звонков в текущий каталог:

    cp /storage/usbdisk1/mikopbx/astlogs/asterisk/cdr.db ./cdr.db 
  7. Конвертация истории звонков в формат MIKOPBX. История в cdr.db будет ОЧИЩЕНА.

    sqlite3 << EOF
    ATTACH DATABASE 'cdr.db' as 'new';
    ATTACH DATABASE 'master.db' as 'old';
    
    delete from new.cdr_general;
    
    INSERT INTO new.cdr_general (
        src_num,
        dst_num,
        src_chan,
        dst_chan,
        start,
        answer,
        endtime,
        duration,
        billsec,
        disposition,
        UNIQUEID,
        did,
        linkedid,
        recordingfile
    )
    SELECT src,
           dst,
           channel,
           dstchannel,
           calldate,
           answer,
           "end",
           duration,
           billsec,
           disposition,
           linkedid || id,
           did,
           linkedid,
           "/storage/usbdisk1/mikopbx/voicemailarchive/monitor/" || strftime("%Y/%m/%d/", calldate) || recordingfile || ".mp3"
      FROM old.PT1C_cdr;
    
    DETACH DATABASE 'new';
    DETACH DATABASE 'old';
    .exit
    EOF
  8. Очистка пустых полей recordingfile в базе данных

    sqlite3 ./cdr.db 'UPDATE cdr_general SET recordingfile="" where recordingfile LIKE "%/.mp3"'
  9. До «2020-02-07» нет записей разговоров. Очистим поле recordingfile

    sqlite3 ./cdr.db 'UPDATE cdr_general SET recordingfile="" where start<"2020-02-07"'
  10. Переместив файл базы данных.

    cp ./cdr.db /storage/usbdisk1/mikopbx/astlogs/asterisk/cdr.db 

Готово! Можно проверять историю звонков в web интерфейсе.

Позвонить в компанию с мобильного и набрав добавочный позвонить сторонней компании

Такой функционал удобен для мобильных сотрудников. Когда важно, чтобы разговор был записан и зафиксирован на АТС в истории звонков. Когда нет возможности использовать софтфон / или «IP-SIM».

  1. Добавьте новое приложение dialplan (см. Приложения диалпланов)

Новое приложение диалпланов
  1. Назначьте внутренний номер, к примеру 2200109

Номер диалплана
  1. Вставьте код во вкладку "Программный код":

<?php

namespace MikoPBX\Core\System;

require_once('Globals.php');

use MikoPBX\Common\Models\ExternalPhones;
use MikoPBX\Core\Asterisk\AGI;
use Phalcon\Mvc\Model\Resultset;

$agi    = new AGI();

$number = substr($agi->request['agi_callerid'],-10);
if(strlen($number) < 7){
    $agi->noop('Count < 7');
    // Проверка на длину номера.
    exit(0);
}
$outPhone = ExternalPhones::findFirst([
  'conditions' => 'dialstring LIKE :number:',
  'bind'       => [
      'number' => "%$number",
  ],
  'hydration' => Resultset::HYDRATE_ARRAYS,
]);

if(count($outPhone) !== 1){
    $agi->noop('ExternalPhones not found '.$number);
    // Проверка на принадлежность номера телефона сотруднику компании.
    exit(0);
}

$agi->set_variable('AGIEXITONHANGUP', 'yes');
$agi->set_variable('AGISIGHUP', 'yes');
$agi->set_variable('__ENDCALLONANSWER', 'yes');
$agi->exec('Ringing', '');
$agi->Answer();

$result      = $agi->getData('vm-enter-num-to-call', 3000, 11);
$selectednum = $result['result']??'';
if(!empty($selectednum)){
    // Все ок. Завершаем вызов.
    $agi->set_variable('__pt1c_UNIQUEID', '');
    $agi->exec(
        'Dial',
        "Local/{$selectednum}@all_peers/n,300," . 'TtekKHhU(dial_answer)b(dial_create_chan,s,1)'
    );
}else{
    $agi->noop('selectednum is empty');
}
Код для создаваемого диалплана
  1. В адресной строке браузера скопируйте ID приложения. Он будет иметь вид «DIALPLAN-APP-6A9902C631C5E7B5AC8F501C559FD678»

ID диалплана
  1. Перейдите в раздел "Кастомизация системных файлов"

Раздел "Кастомизация системных файлов"
  1. Откройте для редактирования файл "extensions.conf"

Конфигурационный файл "extensions.conf"
  1. Вставьте в конец файла следующий код:

[add-trim-prefix-clid-custom]
exten => _.!,1,ExecIf($[ "${EXTEN}" == "h" ]?Hangup()
    same => n,AGI(«DIALPLAN-APP-6A9902C631C5E7B5AC8F501C559FD678.php)
    same => n,Return()
Код для extensions.conf

тут «DIALPLAN-APP-6A9902C631C5E7B5AC8F501C559FD678» - это ID приложения.

Важные моменты

  1. Приложение будет выполнено для всех входящих вызовов

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

  3. Скрипт не является завершенным продуктом, но открыт для кастомизации

Имитация внешних звонков

Настройка имитации внешних звонков

Полезным инструментом для настройки АТС MikoPBX будет имитация входящих и исходящих внешних звонков, чтобы не подключать реального провайдера, тем самым сэкономив.

Имитация звонков

Создание нового SIP-провайдера на АТС

  1. Перейдите в раздел "Маршрутизация" -> "Провайдеры телефонии":

Раздел "Провайдеры телефонии"
  1. Подключите нового SIP-провайдера:

Подключение нового SIP-провайдера
  1. Укажите следующие параметры для нового провайдера:

  • Название - произвольное

  • Тип учетной записи - "Входящая регистрация"

  • Режим DTMF - "auto"

Базовые параметры создаваемого провайдера
  1. В меню создания провайдера, перейдите в "Расширенные настройки":

Отключите использования поля "fromuser".

В поле "Дополнительные параметры" вставьте следующие правки:

[endpoint]
callerid = 79257184275 <79257184275>

Вы можете заменить номер "79257184275" на необходимый Вам

Поле "Дополнительные параметры"

Сохраните настройки и скопируйте:

  • Индентификатор провайдера вида "SIP-TRUNK-704CB9B8". Найти его можно в параметрах или в адресной строке провайдера.

  • Пароль

Идентификатор провайдера

Подключение софтфона для имитации звонка

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

  1. Укажите следующие данные для авторизации:

  • Login - "ProviderID@IPadressOfMikoPBX"

  • Password - "Пароль из карточки настроек провайдера"

Замените:

  • ProviderID на идентификатор Вашего провайдера.

  • IPadressOfMikoPBX на IP-адрес вашей станции.

Данные для авторизации в Zoiper
  1. Завершите процесс авторизации, следуя "Далее". По индикатору подключения провайдера, Вы можете удостовериться в корректности его подключения:

Индикатор провайдера

Настройка маршрутизации

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

Входящая маршрутизация

Параметры входящей маршрутизации

Исходящая маршрутизация

Параметры исходящей маршрутизации

Так же, существует вариант с ручным описанием маршрута для имитации внешнего звонка (Добавлять в конец конфигурационного файла "extensions.conf" в разделе "Кастомизация системных файлов"):

[SIP-TRUNK-704CB9B8-22-outgoing]
exten => _X!,1,NoOp(Outgoing call to ${EXTEN})
same => n,Set(CALLERID(num)=79257184275)
same => n,Dial(PJSIP/${EXTEN}@SIP-TRUNK-704CB9B8)
same => n,Return()

В данном примере описаны правила для исходящих с провайдера "SIP-TRUNK-704CB9B8", номер, который будет отображен при вызове - "79257184275"

В контексте выше, необходимо изменить "SIP-TRUNK-704CB9B8" на Ваш идентификатор провайдера.

SSL сертификат для web-интерфейса MIKOPBX от OPNSense

OPNsense — это операционная система на базе FreeBSD, предназначенная для создания межсетевых экранов (firewall) и маршрутизаторов. Она предоставляет мощные инструменты для управления сетью, включая VPN, фильтрацию трафика, мониторинг и балансировку нагрузки.

OPNSense в своем составе имеет центр сертификации и может выпускать SSL сертификаты для web-интерфейса MIKOPBX.

Для начала необходимо убедится, что центр сертификации OPNSense настроен и корневой сертификат установлен на рабочий ПК пользователя.

Создание сертификата в OPNSense

1. Сгенерируйте сертификат. Перейдите в ваш OPNSense сервер, откройте менеджер сертификатов:

Менеджер сертификатов
  1. Выпустите внутренний сертификат с понятным для вас названием, тип сертификата - сервер, укажите эмитентом ваш внутренний цент сертификации, так же укажите срок действия сертификата в днях.

Параметры сертификата
  1. Далее укажите DNS, настроенный на MIKOPBX.

DNS domain names

Сохраните сертификат в OPNSense.

  1. Сохраните публичный ключ и приватный ключ сертификата на компьютер.

    Найдите в списке сертификатов, ваш сертификат PBX, нажмите скачать.

    Кнопка "Скачать"
  2. В списке скачайте публичный ключ (1) и приватный ключ (2).

    Загрузка публичного и приватного ключа

Установка сертификата в MikoPBX

Перейдите в раздел Общие настройки -> WEB-интерфейс.

Раздел WEB-интерфейс

Откройте ранее скачанные файлы в блокноте. Вставьте содержимое файлов в Web-интерфейс.

Публичный ключ HTTPs содержимое с - BEGIN CERTIFICATE

Приватный ключ HTTPs содержимое с - BEGIN PRIVATE KEY

Сохраните.

Откройте Web-интерфейс MIKOPBX в анонимное режиме браузера используя SSL соединение HTTPS. Ваше подключение защищено.

Настройка индивидуального нерабочего времени для нескольких провайдеров, на одном хосте

Постановка задачи

Имеем две учетные записи от провайдера Zadarma, настроенных в MikoPBX по .

Необходимо для каждого номера Zadarma настроить свое нерабочее время. Например, для номера +7(495)-229-30-42 рабочее время с 9.00 до 18.00 по МСК; для номера +7 (499) 638-25-84 рабочее время с 8.00 до 20.00 по МСК.

Решение

  1. Перейдите в раздел Система → Кастомизация системных файлов.

  1. Откройте для редактирования конфигурационный файл extensions.conf. Установите режим «Добавлять в конец файла». В черное окно добавьте следующий фрагмент кода:

В выше приведенном фрагменте кода Вам необходимо указать логины от Ваших учетных записей провайдеров. В нашем примере использовались следующие данные:

  • 584611 - логин от учетной записи провайдера для номера телефона +7(495)-229-30-42.

Рабочее время с 9.00 до 18.00. Следовательно необходимо задать два интервала для нерабочего времени: 00:00-09:00 и 18:00-23:59.

  • 420296 - логин от учетной записи провайдера для номера телефона +7 (499) 638-25-84.

Рабочее время с 8.00 до 20.00. Следовательно необходимо задать два интервала для нерабочего времени: 00:00-08:00 и 20:00-23:59.

Ниже красным цветом выделены фрагменты, которые Вам необходимо изменить:

Более подробно разберём команду ExecIfTime. Эта команда выполняет указанное приложение Asterisk, если текущее время соответствует заданной спецификации времени. В нашем случае команда выполняет проигрывание звукового файла, расположенного в директории /offload/asterisk/sounds/other/out_work_times в MikoPBX. Синтаксис команды:

  • times - Диапазоны времени в 24-часовом формате

  • weekdays - Дни недели (mon, tue, wed, thu, fri, sat, sun)

  • mdays - Дни месяца (1-31)

  • months - Месяцы (jan, feb, mar, apr и т. д.)

  • appname[(appargs)] - команда Asterisk с указанием параметров вызова

В нашем примере указаны диапазон времени, диапазон дней недели. Вместо указания дней месяцев и месяцев введены *. Этот символ означает «для всех остальных случаев».

Скрытие номера от сотрудника

В ряде случаев сотруднику не положено видеть настоящий номер телефона клиента. Рассмотрим возможный подход в решении этой задачи. Сотруднику будет передаваться подменный номер, на который он сможет перезвонить.

  1. Перейдите в раздел Система → Кастомизация системных файлов

  1. Откройте для редактирования конфигурационный файл modules.conf. Установите режим «Добавлять в конец файла»

  1. Подключим модуль для вычисления хэш суммы:

  1. Откройте для редактирования конфигурационный файл extensions.conf. Установите режим «Добавлять в конец файла»

  1. Опишем контекст для подмены номера

  1. Опишем контекст с номерами, для которых нужно подменять номер

  1. Предусмотрим возможность перезвонить на подменный номер

[public-direct-dial-custom]
exten => _.!,1,NoOp(check time)
    same => n,Gosub(check-out-work-time-custom,${FROM_DID},1)
    same => n,return
	
[check-out-work-time-custom]
exten => 584611,1,NoOp(check time)
    same => n,ExecIfTime(00:00-09:00,mon-fri,*,*?Macro(playback-exit,/offload/asterisk/sounds/other/out_work_times))
    same => n,ExecIfTime(18:00-23:59,mon-fri,*,*?Macro(playback-exit,/offload/asterisk/sounds/other/out_work_times))
    same => n,return
exten => 420296,1,NoOp(check time)
    same => n,ExecIfTime(00:00-08:00,mon-fri,*,*?Macro(playback-exit,/offload/asterisk/sounds/other/out_work_times))
    same => n,ExecIfTime(20:00-23:59,mon-fri,*,*?Macro(playback-exit,/offload/asterisk/sounds/other/out_work_times))
    same => n,return
ExecIfTime(times,weekdays,mdays,months?appname[(appargs)])
ExecIfTime(00:00-08:00,mon-fri,*,*?Macro(playback-exit,/offload/asterisk/sounds/other/out_work_times))
инструкции
Две учетные записи
Раздел "Кастомизация системных файлов"
Код в конец файла extensions.conf
Фрагменты для изменения
load => func_md5.so
[dial_create_chan-custom]
exten => s,1,NoOp()
    ; Только для входящих; 
    same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local" || "${FROM_DID}x" == "x"]?return)
    ; Обработка не требуется, если звонит внутренний номер. 
    same => n,ExecIf(${DIALPLAN_EXISTS(internal,${CONNECTEDLINE(num)},1)}?return)
    ; Обработка не требуется, если номера нет в списке. 
    same => n,ExecIf($[${DIALPLAN_EXISTS(bluring-extensions,${CHANNEL(endpoint)},1)} == 0]?return)
    ; Получим кэш номера. 
    same => n,Set(blNumber=${CONNECTEDLINE(num):-4}*${MD5(${CONNECTEDLINE(num)})})
    same => n,Set(DB(bluring/${blNumber})=${CONNECTEDLINE(num)})
    ; Подмена callerid
    same => n,Set(CONNECTEDLINE(num)=${blNumber})
    same => n,Set(CONNECTEDLINE(name)=${blNumber})
	same => n,return
[bluring-extensions]
; Разрешаем подмену для номера 201
exten => 201,1,NoOp()
; Разрешаем подмену всех четырехзначных номеров
exten => _XXXX,1,NoOp()
[all_peers](+)
exten => _XXXX*.,1,Set(number=${DB(bluring/${EXTEN})})
    same => n,ExecIf($["${number}x" == "x"]?hangup)
    same => n,Goto(all_peers,${number},1)
Раздел "Кастомизация системных файлов"
Режим "Добавлять в конец файла"

Динамические агенты очередей

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

В текущей статье я расскажу как реализовать возможность подключиться и отключиться из очереди средствами набора служебного внутреннего номера.

  1. Создайте новую очередь с четырехзначным внутренним номером. К примеру 2001. (см. документацию «Очереди вызовов»)

  2. Опишите новое «Приложение диалпланов»

  1. Назначьте «Номер для вызова приложения» - 999XXXXX первые три цифры можете переопределить своей комбинацией

Тип кода - «PHP AGI скрипт»

  1. На вкладке «Программный код» вставьте следующее содержимое:

<?php

use MikoPBX\Common\Models\CallDetailRecordsTmp;
use MikoPBX\Common\Models\CallQueueMembers;
use MikoPBX\Common\Models\CallQueues;
use MikoPBX\Common\Models\Extensions;
use MikoPBX\Core\Asterisk\AGI;
use MikoPBX\Core\Asterisk\Configs\QueueConf;

require_once 'Globals.php';

$agi = new AGI();
$agi->answer();

$extension = $agi->get_variable("CHANNEL(peername)", true);
if(empty($extension)){
    $extension = $agi->get_variable("CALLERID(num)", true);
}
$q_exten   = substr($agi->request['agi_extension'], 4);
$add_agent = substr($agi->request['agi_extension'], 3, 1);

$agi->noop("$extension $q_exten $add_agent");

$res = Extensions::findFirst("number='{$extension}'");
if(!$res){
    // Ошибка, такого внутреннего номера не существует.
    $agi->hangup();
}
$res = CallQueues::findFirst("extension='{$q_exten}'");
if(!$res){
    // Ошибка, такой очереди не существует.
    $agi->hangup();
}
$a_count = CallQueueMembers::maximum([ "queue='{$res->uniqid}'", 'column' => 'priority'] ) + 1;
$member  = CallQueueMembers::findFirst("queue='{$res->uniqid}' AND extension='{$extension}'");

if($add_agent === '1' && !$member){
    $member = new CallQueueMembers();
    $member->extension  = $extension;
    $member->queue      = $res->uniqid;
    $member->priority   = $a_count;
    $member->save();
    QueueConf::queueReload();
}

if($add_agent == false && $member){
    $member->delete();
    QueueConf::queueReload();
}

$linkedid = $agi->get_variable("CDR(linkedid)", true);
$res = CallDetailRecordsTmp::find("linkedid='{$linkedid}'");
foreach ($res as $data){
    $data->delete();
}
sleep(2);
$agi->hangup();

Нажмите "Сохранить"

Приложение готово!

  1. Наберите комбинацию 99912001 чтобы присоединиться к очереди 2001

  2. Наберите комбинацию 99902001 чтобы отключиться от очереди 2001

Настройка функции "Paging"

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

Данная инструкция подойдет для телефонов:

  • Linksys

  • Cisco

  • Telephone (софтфон)

  • Grandstream

  • microsip (софтфон)

  • Yealink

  • Fanvil

  • Snom

  1. Перейдите в раздел "Кастомизация системных файлов"

Раздел "Кастомизация системных файлов"
  1. Откройте для редактирования файл "/var/spool/cron/crontabs/root"

Файл "crontabs/root"
  1. Добавьте в конец файла следующий код:

*/1 * * * * /bin/touch /etc/asterisk/confbridge.conf > /dev/null 2> /dev/null
Код для файла "crontabs.root"
  1. Перейдите к редактированию файла "modules.conf"

Файл "Modules.conf"
  1. Добавьте следующий код в конец файла:

load => bridge_softmix.so
load => app_confbridge.so
load => app_page.so
Код для "modules.conf"
  1. Перейдите к редактированию файла "extensions.conf"

Файл "extensions.conf"
  1. Добавьте следующий код в конец файла "extensions.conf"

[paging-users] 
exten => _X!,1,Set(dС=${PJSIP_DIAL_CONTACTS(${EXTEN})})
  same => n,ExecIf($["${dС}x" != "x"]?Dial(${dС},,b(paging_create_chan,s,1)))

[paging_create_chan] 
exten => s,1,Set(PJSIP_HEADER(add,Call-Info)=\;answer-after=0) 
  same => n,return
Код для extensions.conf
  1. Перейдите в раздел "Приложения диалпланов", создайте новый диалплан

Новый диалплан
  1. Назначьте внутренний номер, к примеру 2200110. Установите тип кода: ''Диалплан Asterisk''

Настройки диалплана
  1. Перейдите во вкладку "Программный код", вставьте следующий код:

1,Page(Local/202@paging-users&Local/203@paging-users)
Код для диалплана

В коде приложения опишите контакты, кому следует звонить. Контакты перечисляются с разделителем &.

Оценка клиентом качества обслуживания

Совершенствование качества сервиса организации - крайне важная составляющая успешной работы компании. Механизм оценки работы оператора будет полезен любому бизнесу.

В текущей статье предлагаем пример реализации механизма оценки качества клиентом для АТС MikoPBX.

Доработка Dialplan

На АТС предварительно следует закачать файлы записей вопросов / приветствия. Формат записей WAV (Microsoft) signed 16-bit PCM. Файлы можно для удобства разместить в каталоге: /storage/usbdisk1/quality/sounds. В dialplan путь к файлу следует указывать без расширения.

Для начала дополним логику обработки входящих звонков:

1. Перейдите в раздел Маршрутизация → Провайдеры телефонии. Откройте для редактирования учетную запись провайдера для редактирования. Скопируйте в адресной строке ID провайдера, через которого абоненты звонят Вам в компанию. Обращаем Ваше внимание, что в нашем примере используется единственный провайдер Zadarma. Если у Вас настроено подключение нескольких провайдеров, то ниже описанные действия необходимо выполнить для каждого провайдера.

В нашем примере ID провайдера принимает вид: SIP-1687947415

  1. Перейдите в раздел Система → Кастомизация системных файлов.

  1. Откройте для редактирования конфигурационный файл extensions.conf.

  1. Установите режим «Добавлять в конец файла».

  1. В черное окно добавьте следующий фрагмент кода:

[SIP-PROVIDER-SIP-1687947415-after-dial-custom]
exten => _.!,1,Goto(quality-start,s,1)
	same => n,return

[SIP-PROVIDER-SIP-1687947415-outgoing-custom]
exten => _.!,1,Set(DOPTIONS=${DOPTIONS}F(quality-start,s,1))
	same => n,return

[quality-start]
exten => _.!,1,NoOp(--- Quality assessment ---)
	same => n,ExecIf($[${M_DIALSTATUS}!=ANSWER]?return)
	;Описываем путь к файлу завершения разговора. Благодарим за оценку качества. 
	same => n,Set(filename_bye=/storage/usbdisk1/quality/sounds/bye)
	; Описываем пути к файлам опроса. 
	same => n,Set(filename_1=/storage/usbdisk1/quality/sounds/miko_hello)
	same => n,Set(filename_2=/storage/usbdisk1/quality/sounds/q_1)
	same => n,Set(filename_3=/storage/usbdisk1/quality/sounds/q_2)
	same => n,Set(f_num=0);
	same => n,Goto(ivr-quality,s,1)

[ivr-quality]
exten => s,1,NoOP( start ivr quality )
	same => n,Set(f_num=$[${f_num} + 1])
 	same => n,Set(filename=${filename_${f_num}})
	same => n,GotoIf($["x${filename}" == "x"]?ivr-quality,bye,1);
	same => n,Background(${filename})
	same => n,WaitExten(5)

exten => _[1-5],1,NoOP( quality is ${EXTEN})
	; AGI скрипт, который сохранит результат оценки разговора клиентом.
	same => n,AGI(/storage/usbdisk1/quality/quality_agi.php)
	same => n,Goto(ivr-quality,s,1)

exten => _[06-9],Goto(ivr-quality,s,1)

exten => bye,1,ExecIf($["x${filename_bye}" != "x"]?Playback(${filename_bye}));
	same => n,Hangup()

В выше приведенном фрагменте кода Вам необходимо составить правильное наименование контекста. Формат создаваемого контекста:

[ID-ПРОВАЙДЕРА-outgoing-custom]
[ID-ПРОВАЙДЕРА-after-dial-custom]
  • ID-ПРОВАЙДЕРА - значение, которое вы сохранили на первом шаге данной инструкции. В нашем примере это SIP-PROVIDER-1687947415.

Скрипт обработки результата оценки

Файл следует сохранить на АТС по пути /storage/usbdisk1/quality/quality_agi.php Создать файл можно используя файловый менеджер WinSCP Файлу следует установить права доступа на выполнение. Подключитесь по SSH и выполните команду

chmod +x /storage/usbdisk1/quality/quality_agi.php

Пример реализации quality_agi.php:

#!/usr/bin/php
<?php
require_once 'phpagi.php';
require_once 'globals.php';

$agi 		= new AGI();
$linkedid   = $agi->get_variable('CDR(linkedid)', true);

$arr = [
    'quality'   => $agi->request['agi_extension'],
    'f_num'     => $agi->get_variable('f_num', true),
    'filename'  => $agi->get_variable('filename', true),
    // 'Оцененный оператор:' => $operator,
    'linkedid'  => $linkedid,
    'date'      => date('Y-m-d H:i:s'),
    'callerid'  => $agi->request['agi_callerid']
];

$file_log = '/storage/usbdisk1/quality/'.$linkedid.'.log';
Util::mw_mkdir(dirname($file_log));
file_put_contents($file_log, json_encode($arr)."\n", FILE_APPEND);

Результат оценки будет сохранятся в файлы вида /storage/usbdisk1/quality/<ID>.log

Пример файла:

{"quality":"1","f_num":"1","filename":"\/offload\/asterisk\/sounds\/other\/miko_hello","linkedid":"mikopbx-1574331248.66","date":"2019-11-21 13:14:13","callerid":"79265775289"}
{"quality":"2","f_num":"2","filename":"beep","linkedid":"mikopbx-1574331248.66","date":"2019-11-21 13:14:15","callerid":"79265775289"}
{"quality":"3","f_num":"3","filename":"\/offload\/asterisk\/sounds\/other\/out_work_times","linkedid":"mikopbx-1574331248.66","date":"2019-11-21 13:14:16","callerid":"79265775289"}

Пауза для агента очереди

Для случая, когда сотрудник отошел и не может ответить на вызов бывает удобно поставить агента на паузу. К примеру сотрудник набирает специальный добавочный номер *46 и уходит по на обед.

Новые вызовы сотруднику перестанут поступать.

Когда сотрудник возвращается, снова набирает номер *46 и отключает паузу. В современных телефонах все можно свести к нажатию одной кнопки.

  1. Перейдите в раздел "Модули" -> "Приложения диалпланов"

Раздел "Приложения диалпланов"
  1. Создайте новый диалплан.

Создание нового диалплана
  1. Укажите название, а так же номер диалпана (в нашем случае - 2200105). В качестве типа кода укажите "Диалплан Asterisk"

Настройки нового диалплана
  1. Перейдите во вкладку "Программный код". Вставьте следующий код в черную область:

1,Answer()
n,Set(PeerNumber=${CHANNEL(endpoint)})
n,Set(MemberStatus=${DB(QueueMemberOnPause/${PeerNumber}})
n,Set(AppName=${IF($[ "${MemberStatus}" != "1" ]?PauseQueueMember:UnpauseQueueMember)})
n,Set(NewMemberStatus=${IF($[ "${MemberStatus}" == "1" ]?0:1)})
n,Exec(${AppName}(,Local/${PeerNumber}@internal/n))
n,Set(DB(QueueMemberOnPause/${PeerNumber})=${NewMemberStatus})
n,Playback(beep)
n,Hangup()
Код для диалплана
  1. Перейдите в раздел «Кастомизация системных файлов»

Раздел "Кастомизация системных файлов"
  1. Откройте для редактирования файл «/etc/asterisk/extensions.conf»

Конфигурационный файл "extensions.conf"
  1. Вставьте в конец файла следующий код:

[all_peers](+)
exten => *46,1,Goto(applications,)
Код для extensions.conf

Уникальная фоновая музыка для очереди

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

  1. Перейдите в раздел «Телефония» - «Звуковые файлы» - «Музыка на удержании»

Раздел "Звуковые файлы"
  1. Добавьте медиафайлы:

Новый звуковой файл
  1. После сохранения медиа файла скопируйте его идентификатор из адресной строки браузера. К примеру в ссылке вида «http://192.168.0.41/admin-cabinet/sound-files/modify/5» идентификатором является число 5.

Идентификатор медиа файла
  1. Перейдите в раздел «Система» - «Кастомизация системных файлов»

Раздел "Кастомизация системных файлов"
  1. Откройте для редактирования файл «/etc/asterisk/extensions.conf»

Конфигурационный файл "extensions.conf"
  1. Вставьте в конец файла следующий код:

[queue-pre-dial-custom]
exten => 2001,1,Set(CHANNEL(musicclass)=moh-5)
exten => 2002,1,Set(CHANNEL(musicclass)=moh-6)
exten => _X!,2,return
Код для extensions.conf

Согласно этому примеру для очереди с номером «2001» будет воспроизводится в фоне файл с идентификатором 5, для очереди «2002» файл с идентификатором 6

Ограничить количество авторизаций на одном SIP аккаунте

  1. Перейдите к редактированию учетной записи сотрудника.

Редактирование учетной записи сотрудника
  1. В поле «Дополнительные параметры», добавьте:

[aor]
max_contacts = 1
Дополнительные параметры в учетной записи сотрудника

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