/ #linux 

IP-телефонія на базі Asterisk. Частина 3: Логіка обробки дзвінків (Dialplan)

Цикл статей по розгортанню IP-телефонії на базі Asterisk. Фактично це моя проектна робота на отримання відповідного сертифікату одного з навчальних центрів. Робота була захищена, сертифікат отриманий, все написане тестувалось і є повтінстю робочою реалізацією. Інформація в статті і версії програмного забезбечення актуальні на 2017 рік.

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'

В наступній статті будемо налаштовувати голосове меню.

Author

Олександр Бобилєв

Залишаю собі право використовувати ненормативну (але інформативну) лексику там, де звичайні слова втрачають сенс і не відображають всієї палітри почуттів, від споглядання навколишньої дійсності.