IP-телефонія на базі Asterisk. Частина 3: Логіка обробки дзвінків (Dialplan)
Цикл статей по розгортанню IP-телефонії на базі Asterisk. Фактично це моя проектна робота на отримання відповідного сертифікату одного з навчальних центрів. Робота була захищена, сертифікат отриманий, все написане тестувалось і є повтінстю робочою реалізацією. Інформація в статті і версії програмного забезбечення актуальні на 2017 рік.
- частина 1 - Встановлення сервера Asterisk
- частина 2 - Налаштування SIP
3. Логіка обробки дзвінків (Dialplan)
3.1 План дозвона на разні напрямки
Створимо кілька контекстів для обробки дзвінків:
- call-local - контекст для дзвінків між внутрішніми номерами
- call-in - контекст для вхідних дзвінків з “зовнішніх” номерів
- call-out - контекст для вихідних дзвінків на “зовнішні” номери Робимо резервну копію файлу extensions.conf і створюємо новий файл для налаштування плану дозвону:
mv extensions.conf extensions.conf.default
touch extensions.conf
Вносимо в створений файл такі контексти:
[general]
static=yes
writeprotect=no
[globals]
[default]
;внутрішні лінії
[call-local]
exten => _XXX,1,Dial(SIP/${EXTEN})
exten => _XXX,n,Hangup()
;вихідні дзвінки на зовнішні лінії
[call-out]
exten => _XXX.,1,Dial(SIP/${EXTEN}@zadarma)
exten => _XXX.,n,Hangup()
;вхідні дзвінки з зовнішніх ліній
[call-in]
exten => YYYYYY,1,Dial(SIP/101)
[manager]
include => call-local
include => call-out
Перевіряємо дзвінки між внутрішніми лініями:
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
-- Executing [102@manager:1] Dial("SIP/101-0000002a", "SIP/102") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/102
-- SIP/102-0000002b is ringing
-- SIP/102-0000002b answered SIP/101-0000002a
-- Channel SIP/102-0000002b joined 'simple_bridge' basic-bridge <70ea55b8-8b22-42e3-9add-50c67bdf80ab>
-- Channel SIP/101-0000002a joined 'simple_bridge' basic-bridge <70ea55b8-8b22-42e3-9add-50c67bdf80ab>
> Bridge 70ea55b8-8b22-42e3-9add-50c67bdf80ab: switching from simple_bridge technology to native_rtp
> Locally RTP bridged 'SIP/101-0000002a' and 'SIP/102-0000002b' in stack
> Locally RTP bridged 'SIP/101-0000002a' and 'SIP/102-0000002b' in stack
-- Channel SIP/102-0000002b left 'native_rtp' basic-bridge <70ea55b8-8b22-42e3-9add-50c67bdf80ab>
-- Channel SIP/101-0000002a left 'native_rtp' basic-bridge <70ea55b8-8b22-42e3-9add-50c67bdf80ab>
== Spawn extension (manager, 102, 1) exited non-zero on 'SIP/101-0000002a'
== Using SIP RTP CoS mark 5
-- Executing [101@manager:1] Dial("SIP/102-0000002c", "SIP/101") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/101
-- SIP/101-0000002d is ringing
-- SIP/101-0000002d answered SIP/102-0000002c
-- Channel SIP/101-0000002d joined 'simple_bridge' basic-bridge <10e80012-fb40-47ab-be85-7d76cb584588>
-- Channel SIP/102-0000002c joined 'simple_bridge' basic-bridge <10e80012-fb40-47ab-be85-7d76cb584588>
> Bridge 10e80012-fb40-47ab-be85-7d76cb584588: switching from simple_bridge technology to native_rtp
> Locally RTP bridged 'SIP/102-0000002c' and 'SIP/101-0000002d' in stack
> Locally RTP bridged 'SIP/102-0000002c' and 'SIP/101-0000002d' in stack
-- Channel SIP/101-0000002d left 'native_rtp' basic-bridge <10e80012-fb40-47ab-be85-7d76cb584588>
-- Channel SIP/102-0000002c left 'native_rtp' basic-bridge <10e80012-fb40-47ab-be85-7d76cb584588>
== Spawn extension (manager, 101, 1) exited non-zero on 'SIP/102-0000002c'
Перевіряємо дзвінки на зовнішні лінії, а саме на номер XXXXXX провайдера Zadarma.
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
-- Executing [XXXXXX@manager:1] Dial("SIP/101-00000035", "SIP/XXXXXX@zadarma") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/XXXXXX@zadarma
-- SIP/zadarma-00000036 is ringing
-- SIP/zadarma-00000036 answered SIP/101-00000035
-- Channel SIP/zadarma-00000036 joined 'simple_bridge' basic-bridge <d19036d2-735c-4c43-b2b5-9ac8d3b040f6>
-- Channel SIP/101-00000035 joined 'simple_bridge' basic-bridge <d19036d2-735c-4c43-b2b5-9ac8d3b040f6>
> Bridge d19036d2-735c-4c43-b2b5-9ac8d3b040f6: switching from simple_bridge technology to native_rtp
> Locally RTP bridged 'SIP/101-00000035' and 'SIP/zadarma-00000036' in stack
> Locally RTP bridged 'SIP/101-00000035' and 'SIP/zadarma-00000036' in stack
-- Channel SIP/101-00000035 left 'native_rtp' basic-bridge <d19036d2-735c-4c43-b2b5-9ac8d3b040f6>
== Spawn extension (manager, XXXXXX, 1) exited non-zero on 'SIP/101-00000035'
-- Channel SIP/zadarma-00000036 left 'native_rtp' basic-bridge <d19036d2-735c-4c43-b2b5-9ac8d3b040f6>
Перевіряємо можливість додзвонитися на наш Asterisk з зовнішнього номера, для цього дзвонимо на номер YYYYYY провайдера Zadarma, який вважаємо “зовнішнім” номером нашої компанії:
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
-- Executing [YYYYYY@call-in:1] Dial("SIP/zadarma-00000004", "SIP/101") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/101
-- SIP/101-00000005 is ringing
-- SIP/101-00000005 answered SIP/zadarma-00000004
-- Channel SIP/101-00000005 joined 'simple_bridge' basic-bridge <de21e7c6-f846-401c-8eaa-ccb947a8c88b>
-- Channel SIP/zadarma-00000004 joined 'simple_bridge' basic-bridge <de21e7c6-f846-401c-8eaa-ccb947a8c88b>
> Bridge de21e7c6-f846-401c-8eaa-ccb947a8c88b: switching from simple_bridge technology to native_rtp
> Locally RTP bridged 'SIP/zadarma-00000004' and 'SIP/101-00000005' in stack
> Locally RTP bridged 'SIP/zadarma-00000004' and 'SIP/101-00000005' in stack
-- Channel SIP/101-00000005 left 'native_rtp' basic-bridge <de21e7c6-f846-401c-8eaa-ccb947a8c88b>
-- Channel SIP/zadarma-00000004 left 'native_rtp' basic-bridge <de21e7c6-f846-401c-8eaa-ccb947a8c88b>
== Spawn extension (call-in, YYYYYY, 1) exited non-zero on 'SIP/zadarma-00000004'
3.2 Ролі і політики дзвінків
Доповнимо файл extensions.conf контекстами для різних ролей компанії, застосуємо до них такі політики дзвінків:
- керуючий персонал - дзвінки на будь-які напрямки, включаючи міжнародні;
- відділ продажів, відділ закупівель, секретар - заборонені дзвінки на міжнародні лінії;
- склад - заборонені дзвінки на зовнішні лінії;
- технічний відділ - заборонені дзвінки до керуючого персоналу і на зовнішні лінії.
[general]
static=yes
writeprotect=no
[globals]
[default]
;внутрішні лінії за виключенням manager
[call-local]
exten => _[2-6],1,Dial(SIP/${EXTEN},20)
exten => _[2-6],n,Hangup()
;внутрішні лінії керівництва
[call-local-manager]
exten => _1XX,1,Dial(SIP/${EXTEN},20)
exten => _1XX,n,Hangup()
;вихідні дзвінки на всі зовнішні лінії, в тому числі міжнародний з'язок
[call-out-world]
exten => _XXXXXXXXXXXX,1,Dial(SIP/${EXTEN}@zadarma,20)
exten => _XXXXXXXXXXXX,n,Hangup()
;вихідні дзвінки на зовнішні лінії в межах України
[call-out-ua]
exten => _38XXXXXXXXXX,1,Dial(SIP/${EXTEN}@zadarma,20)
exten => _38XXXXXXXXXX,n,Hangup()
;вхідні дзвінки з зовнішніх ліній
[call-in]
exten => YYYYYY,1,Dial(SIP/101)
[manager]
include => call-local-manager
include => call-local
include => call-out-world
[sales]
include => call-local-manager
include => call-local
include => call-out-ua
[buyings]
include => call-local-manager
include => call-local
include => call-out-ua
[warehouse]
include => call-local-manager
include => call-local
[it]
include => call-local
[reception]
include => call-local-manager
include => call-local
include => call-out-ua
Перевіряємо заборону дзвінків на групу manager:
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
[2017-05-01 19:35:30] NOTICE[2173][C-00000028]: chan_sip.c:26374 handle_request_invite: Call from '501' (192.168.1.101:5060) to extension '380938694966' rejected because extension not found in context 'it'.
Провереяем звонки на внешние линии:
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
-- Executing [380938694966@manager:1] Dial("SIP/102-0000003b", "SIP/380938694966@zadarma,30") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/380938694966@zadarma
-- SIP/zadarma-0000003c is making progress passing it to SIP/102-0000003b
-- SIP/zadarma-0000003c is ringing
> 0xb3286448 -- Probation passed - setting RTP source address to 192.168.1.105:7078
> 0xb690fc70 -- Probation passed - setting RTP source address to 185.45.152.163:15936
== Spawn extension (manager, 380938694966, 1) exited non-zero on 'SIP/102-0000003b'
3.3 Запис дзвінків
Додамо функцію запису дзвінків в форматі mp3 “на льоту”. За замовчуванням запис дзвінків буде включена, але з можливістю відключити її під час розмови. Для підтримки формату mp3 встановимо в системі пакет lame:
cd /usr/src/
wget https://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz
tar vxfz lame-3.99.5.tar.gz
rm -f lame-3.99.5.tar.gz
cd lame-3.99.5
./configure
make && make install
Додаємо можливість запису дзвінків в діалплан:
[general]
static=yes
writeprotect=no
[globals]
RECORDING=0
[default]
;MixMonitor
[macro-recording]
exten => s,1,GoToIf($["${RECORDING}" = "1"]?yes:no);
exten => s,n(yes),Set(fname=${STRFTIME(${EPOCH},,%Y)}/${STRFTIME(${EPOCH},,%Y-%m)}/${STRFTIME(${EPOCH},,%Y-%m-%d)}/${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${ARG1}-${ARG2})
exten => s,n,Set(fname=${STRFTIME(${EPOCH},,%Y)}/${STRFTIME(${EPOCH},,%Y-%m)}/${STRFTIME(${EPOCH},,%Y-%m-%d)}/${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${ARG1}-${ARG2})
exten => s,n,Set(DIR_RECORDS=/var/spool/asterisk/monitor/)
exten => s,n,NoOp(Dir - ${STRFTIME(${EPOCH},,%Y)}/${STRFTIME(${EPOCH},,%Y-%m)}/${STRFTIME(${EPOCH},,%Y-%m-%d)})
exten => s,n,Set(monopt=nice -n 19 /usr/local/bin/lame -b 32 --silent "${DIR_RECORDS}${fname}.wav" "${DIR_RECORDS}${fname}.mp3" && rm -f "${DIR_RECORDS}${fname}.wav" && chmod o+r "${DIR_RECORDS}${fname}.mp3");
exten => s,n,MixMonitor(${DIR_RECORDS}${fname}.wav,b,${monopt});
exten => s,n(no),Verbose(Exit record);
;внутрішні лінії за виключенням manager
[call-local]
exten => _[2-6],1,Set(RECORDING=0)
exten => _[2-6],n,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _[2-6],n,Dial(SIP/${EXTEN},20)
exten => _[2-6],n,Hangup()
;внутрішні лінії керівництва
[call-local-manager]
exten => _1XX,1,Set(RECORDING=1)
exten => _1XX,n,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _1XX,n,Dial(SIP/${EXTEN},20)
exten => _1XX,n,Hangup()
;вихідні дзвінки на всі зовнішні лінії, в тому числі міжнародний з'язок
[call-out-world]
exten => _XXXXXXXXXXXX,1,Set(RECORDING=1)
exten => _XXXXXXXXXXXX,n,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _XXXXXXXXXXXX,n,Dial(SIP/${EXTEN}@zadarma,20)
exten => _XXXXXXXXXXXX,n,Hangup()
;вихідні дзвінки на зовнішні лінії в межах України
[call-out-ua]
exten => _38XXXXXXXXXX,1,Set(RECORDING=1)
exten => _38XXXXXXXXXX,n,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _38XXXXXXXXXX,n,Dial(SIP/${EXTEN}@zadarma,20)
exten => _38XXXXXXXXXX,n,Hangup()
;вхідні дзвінки з зовнішніх ліній
[call-in]
exten => YYYYYY,1,Set(RECORDING=1)
exten => YYYYYY,1,Macro(recording,${CALLERID(num)},${EXTEN})
exten => YYYYYY,n,Dial(SIP/501)
[manager]
include => call-local-manager
include => call-local
include => call-out-world
[sales]
include => call-local-manager
include => call-local
include => call-out-ua
[buyings]
include => call-local-manager
include => call-local
include => call-out-ua
[warehouse]
include => call-local-manager
include => call-local
[it]
include => call-local
[reception]
include => call-local-manager
include => call-local
include => call-out-ua
Запис дзвінків в контексті call-in:
== Using SIP RTP CoS mark 5
-- Executing [YYYYYY@call-in:1] Macro("SIP/zadarma-00000000", "recording,XXXXXX,YYYYYY") in new stack
-- Executing [s@macro-recording:1] GotoIf("SIP/zadarma-00000000", "1?yes:no") in new stack
-- Goto (macro-recording,s,2)
-- Executing [s@macro-recording:2] Set("SIP/zadarma-00000000", "fname=2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY") in new stack
-- Executing [s@macro-recording:3] Set("SIP/zadarma-00000000", "fname=2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY") in new stack
-- Executing [s@macro-recording:4] Set("SIP/zadarma-00000000", "DIR_RECORDS=/var/spool/asterisk/monitor/") in new stack
-- Executing [s@macro-recording:5] NoOp("SIP/zadarma-00000000", "Dir - 2017/2017-05/2017-05-02") in new stack
-- Executing [s@macro-recording:6] Set("SIP/zadarma-00000000", "monopt=nice -n 19 /usr/local/bin/lame -b 32 --silent "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.mp3" && rm -f "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" && chmod o+r "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.mp3"") in new stack
-- Executing [s@macro-recording:7] MixMonitor("SIP/zadarma-00000000", "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav,b,nice -n 19 /usr/local/bin/lame -b 32 --silent "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.mp3" && rm -f "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" && chmod o+r "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.mp3"") in new stack
-- Executing [s@macro-recording:8] Verbose("SIP/zadarma-00000000", "Exit record") in new stack
Exit record
-- Executing [YYYYYY@call-in:2] Dial("SIP/zadarma-00000000", "SIP/501") in new stack
== Begin MixMonitor Recording SIP/zadarma-00000000
== Using SIP RTP CoS mark 5
-- Called SIP/501
-- SIP/501-00000001 is ringing
-- SIP/501-00000001 answered SIP/zadarma-00000000
-- Channel SIP/501-00000001 joined 'simple_bridge' basic-bridge <860a4d95-f7de-4974-86ce-da5f4336ff02>
-- Channel SIP/zadarma-00000000 joined 'simple_bridge' basic-bridge <860a4d95-f7de-4974-86ce-da5f4336ff02>
-- Channel SIP/501-00000001 left 'simple_bridge' basic-bridge <860a4d95-f7de-4974-86ce-da5f4336ff02>
-- Channel SIP/zadarma-00000000 left 'simple_bridge' basic-bridge <860a4d95-f7de-4974-86ce-da5f4336ff02>
== Spawn extension (call-in, YYYYYY, 2) exited non-zero on 'SIP/zadarma-00000000'
== MixMonitor close filestream (mixed)
== Executing [nice -n 19 /usr/local/bin/lame -b 32 --silent "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-XXXXXX.mp3" && rm -f "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.wav" && chmod o+r "/var/spool/asterisk/monitor/2017/2017-05/2017-05-02/1493749769.0-2017-05-02-21_29-XXXXXX-YYYYYY.mp3"]
== End MixMonitor Recording SIP/zadarma-00000000
Отсутствие записи в контексте call-local:
asterisk-centos*CLI>
== Using SIP RTP CoS mark 5
-- Executing [501@manager:1] Set("SIP/102-00000010", "RECORDING=0") in new stack
-- Executing [501@manager:2] Macro("SIP/102-00000010", "recording,102,501") in new stack
-- Executing [s@macro-recording:1] GotoIf("SIP/102-00000010", "0?yes:no") in new stack
-- Goto (macro-recording,s,8)
-- Executing [s@macro-recording:8] Verbose("SIP/102-00000010", "Exit record") in new stack
Exit record
-- Executing [501@manager:3] Dial("SIP/102-00000010", "SIP/501,20") in new stack
== Using SIP RTP CoS mark 5
-- Called SIP/501
-- SIP/501-00000011 is ringing
-- SIP/501-00000011 answered SIP/102-00000010
-- Channel SIP/501-00000011 joined 'simple_bridge' basic-bridge <f219765d-eced-41e3-8a5d-4e27d5651e14>
-- Channel SIP/102-00000010 joined 'simple_bridge' basic-bridge <f219765d-eced-41e3-8a5d-4e27d5651e14>
> Bridge f219765d-eced-41e3-8a5d-4e27d5651e14: switching from simple_bridge technology to native_rtp
> Locally RTP bridged 'SIP/102-00000010' and 'SIP/501-00000011' in stack
> Locally RTP bridged 'SIP/102-00000010' and 'SIP/501-00000011' in stack
-- Channel SIP/501-00000011 left 'native_rtp' basic-bridge <f219765d-eced-41e3-8a5d-4e27d5651e14>
-- Channel SIP/102-00000010 left 'native_rtp' basic-bridge <f219765d-eced-41e3-8a5d-4e27d5651e14>
== Spawn extension (manager, 501, 3) exited non-zero on 'SIP/102-00000010'
В наступній статті будемо налаштовувати голосове меню.
- частина 1 - Встановлення сервера Asterisk
- частина 2 - Налаштування SIP