Step-by-Step guide on how to implement Asterisk in Real Time

After an exhaustive investigation throughout the internet, various Google searches later, we found out that information about Asterisk in RealTime is too old. Most of it was from about 2005 or 2015 at best. Apparently, nobody has been interested on transmitting the knowledge of this interesting way of programming Asterisk.

Read our tutorials and guides on how to implement new tools and technologies for your business with VitalPBX here.

Due to what was expressed beforehand, we gave ourselves the task of searching all of the available information and compile it all in one single guide that will make life easier to everyone interested on implementing Asterisk Real Time. The best kind of knowledge is the one that is shared with everyone.

1.-Recommendations

  1. We do not recommend the utilization of the Dial Plan in Real Time. If we have a Dial Plan that is too big, each time that we make a call, the database queries could overload the system.
  2. On this guide we are using CentOS 7, however, you would be able to use CentOS 8 or Ubuntu if you so desire.
  3. Take into account that Asterisk has already deprecated the following applications:
    • meetme, from various versions ago, this was substituted with confbridge which currently does not support Real-Time.
    • SIP, on version 17 of Asterisk, SIP has been deprecated, however, on this guide we will cover this type of devices.
  4. Never do this implementation on a production server. Test everything, and make sure that it is suited to your usage.

2.- Installation

2.1.- Firewall Configuration

CentOS 7 generally comes with the firewall activated, and the ports 5060-5063 and 10000-20000 are blocked. Due to this we could have problems at the moment of wanting to register SIP or PJSIP extensions. Coming up, we will apply the following firewall rules to prevent this issue.

[root@localhost ~]# systemctl start firewalld
[root@localhost ~]# systemctl enable firewalld
[root@localhost ~]# firewall-cmd --zone=public --add-port=5060-5063/udp --permanent
[root@localhost ~]# firewall-cmd --zone=public --add-port=5060-5063/tcp --permanent
[root@localhost ~]# firewall-cmd --zone=public --add-port=10000-20000/udp --permanent

2.2.- Installing Asterisk 17

On this guide we will be implying that you already have a machine with CentOS 7 Minimal installed, for which we will start with the installation process of Asterisk 17 and its dependencies. To enter the CentOS 7 console, you can start an SSH client, e.g. PuTTY.

Install CentOS 7.8 and update it to the latest version

[root@localhost ~]# yum update -y

Disable SELINUX on CentOS 7

[root@localhost ~]# vi /etc/selinux/config

Change the line:

SELINUX=enforcing
to
SELINUX=disabled

[root@localhost ~]# reboot

Install Dependencies

[root@localhost ~]# yum install -y epel-release dmidecode gcc-c++ ncurses-devel libxml2-devel make wget openssl-devel newt-devel kernel-devel sqlite-devel libuuid-devel gtk2-devel jansson-devel binutils-devel libedit libedit-devel

Create the user ‘asterisk’. Use a password of your choosing

[root@localhost ~]# adduser asterisk -c "Asterisk User"
[root@localhost ~]# passwd asterisk
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@localhost ~]# usermod -aG wheel asterisk

Now we start the install process of Asterisk 17

[root@localhost ~]# cd /usr/src
[root@localhost src]# wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-17-current.tar.gz
[root@localhost src]# tar -zxvf asterisk-17-current.tar.gz
[root@localhost src]# cd asterisk-17.4.0
[root@localhost asterisk-17.4.0]# yum install svn -y
[root@localhost asterisk-17.4.0]# ./contrib/scripts/get_mp3_source.sh
[root@localhost asterisk-17.4.0]# contrib/scripts/install_prereq install
[root@localhost asterisk-17.4.0]# ./configure --libdir=/usr/lib64 --with-jansson-bundled --with-pjproject-bundled

Then, we proceed to make menuselect

[root@localhost asterisk-17.4.0]# make menuselect

We make sure that on the Channel Drivers chan_sip is selected. Here, we can also select different audios and codecs if you like, for example, opus. After selecting everything we need, we proceed to Save & Exit.

Now we will proceed with the following

[root@localhost asterisk-17.4.0]# make && make install
[root@localhost asterisk-17.4.0]# make samples
[root@localhost asterisk-17.4.0]# make config
[root@localhost asterisk-17.4.0]# chown asterisk. /var/run/asterisk
[root@localhost asterisk-17.4.0]# chown asterisk. -R /etc/asterisk
[root@localhost asterisk-17.4.0]# chown asterisk. -R /var/{lib,log,spool}/asterisk
[root@localhost asterisk-17.4.0]# chkconfig asterisk on
[root@localhost asterisk-17.4.0]# systemctl start asterisk
[root@localhost asterisk-17.4.0]# asterisk -rvvvvvvvvvvvvvvvvvvv
Asterisk 17.4.0, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 17.4.0 currently running on localhost (pid = 91658)
localhost*CLI>

CONGRATULATIONS! You have successfully installed Asterisk 17!

2.3.- Installing Mariadb and dependencies.

For Asterisk Real-Time to work, it is necessary to install MariaDB, since the Real-Time application works with data bases and is connected through ODBC.

[root@localhost ~]# yum install -y mysql-connector-odbc mariadb mariadb-server
[root@localhost ~]# systemctl enable mariadb
[root@localhost ~]# systemctl start mariadb

From version 12, the creation of the tables for Asterisk Real-Time is done using alembic. With the same application, it is possible to migrate to the latest version of Asterisk and update the tables created with version 11 or prior. First, we need to install some dependencies:

[root@localhost ~]# yum install MySQL-python python-pip -y

Afterwards, we install alembic using pip:

[root@localhost ~]# pip install alembic

Since the creation/update of the tables is based of a configuration file, we modify it:

[root@localhost ~]# cd /usr/src/asterisk-17.4.0/contrib/ast-db-manage/
[root@localhost ast-db-manage]# mv config.ini.sample config.ini
[root@localhost ast-db-manage]# vi config.ini

We change the following line:
sqlalchemy.url = mysql://user:pass@localhost/asterisk
with:
sqlalchemy.url = mysql://root:@localhost/asterisk

The syntax of the line is: Database engine, user, password, domain/IP, database. With this line, we create the connection to the database. We Save changes and proceed to the creation of the database:

[root@localhost ~]# mysql -u root 
MariaDB [(none)]> create database asterisk;
MariaDB [(none)]> exit;

We create/update the tables with the following command:

[root@localhost ~]# cd /usr/src/asterisk-17.4.0/contrib/ast-db-manage/
[root@localhost ast-db-manage]# alembic -c config.ini upgrade head

We enter MariaDB once again:

[root@localhost ~]# mysql -u root 
MariaDB [(none)]> use asterisk;
MariaDB [(asterisk)]> show tables;
+-----------------------------+
| Tables_in_asterisk          |
+-----------------------------+
| alembic_version_config      |
| extensions                  |
| iaxfriends                  |
| meetme                      |
| musiconhold                 |
| musiconhold_entry           |
| ps_aors                     |
| ps_asterisk_publications    |
| ps_auths                    |
| ps_contacts                 |
| ps_domain_aliases           |
| ps_endpoint_id_ips          |
| ps_endpoints                |
| ps_globals                  |
| ps_inbound_publications     |
| ps_outbound_publishes       |
| ps_registrations            |
| ps_resource_list            |
| ps_subscription_persistence |
| ps_systems                  |
| ps_transports               |
| queue_members               |
| queue_rules                 |
| queues                      |
| sippeers                    |
| voicemail                   |
+-----------------------------+
26 rows in set (0.00 sec)

Now, we create a username that has the privileges to work with the created database:

MariaDB [asterisk]> grant all privileges on asterisk.* to 'asterisk'@'localhost' identified by 'asterisk';
Query OK, 0 rows affected (0.00 sec)
MariaDB [asterisk]> FLUSH Privileges;
MariaDB [asterisk]> exit;

For some reason that is unknown to us, on the ‘sippeers’ table, the permit field is created before the deny field. This causes that when you create an extension with SIP devices, it gives us an ACL error at the moment of registration. To prevent this problem, we recommend the deletion of the two fields and make them again, but the deny field first and then the permit field. So, we do the following:

MariaDB [asterisk]> ALTER TABLE sippeers DROP COLUMN deny;
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0
MariaDB [asterisk]> ALTER TABLE sippeers DROP COLUMN permit;
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0
MariaDB [asterisk]> ALTER TABLE sippeers ADD(deny varchar(95) Default '0.0.0.0/0');
Query OK, 1 row affected (0.04 sec)
Records: 1  Duplicates: 0  Warnings: 0
MariaDB [asterisk]> ALTER TABLE sippeers ADD(permit varchar(95) Default '0.0.0.0/0');
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0
MariaDB [asterisk]> exit;

2.4.- Asterisk Configurations

Now, we proceed to the configuration of ODBC and Asterisk so that Real-Time works properly. The odbcinst.ini file, available on the etc folder, we leave it with the default configurations. We create the odbc.ini file, where we configure the connection to the Asterisk Database:

[root@localhost ~]# vi /etc/odbc.ini
[asterisk]
Description = MySQL Asterisk
Driver = MySQL
Database = asterisk
Server = localhost
User = asterisk
Password = asterisk
Port = 3306
Option = 3

We save changes and verify that the connection is working properly:

[root@localhost ~]# isql asterisk asterisk asterisk
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> quit;

Perfect! Now, we proceed to the Asterisk configurations and the the following to the end:

[root@localhost ~]# vi /etc/asterisk/res_odbc.conf
[asterisk]
enabled => yes
dsn => asterisk
username => asterisk
password => asterisk
pre-connect => yes
sanitysql => select 1
max_connections => 20
connect_timeout => 5
negative_connection_cache => 600

Now, we configure the Asterisk file, extconfig.conf

[root@localhost ~]# vi /etc/asterisk/extconfig.conf
;
; Static and realtime external configuration
; engine configuration
;
; See https://wiki.asterisk.org/wiki/display/AST/Realtime+Database+Configuration
; for basic table formatting information.
;
[settings]
ps_endpoints => odbc,asterisk
ps_auths => odbc,asterisk
ps_aors => odbc,asterisk
ps_domain_aliases => odbc,asterisk
ps_endpoint_id_ips => odbc,asterisk
ps_contacts => odbc,asterisk
voicemail => odbc,asterisk
queues => odbc,asterisk
queue_members => odbc,asterisk
sipusers => odbc,asterisk
sippeers => odbc,asterisk
extensions => odbc,asterisk

As you can see, we are configuring the PJSIP Devices (everything that starts with ps), Voicemail, SIP Devices, Queues, Queue Members, and extensions for Real-Time.

Now, we configure the Asterisk file, pjsip.conf. We add to the end the following lines.

[root@localhost ~]# vi /etc/asterisk/pjsip.conf
[system]
type=system
timer_t1=500
timer_b=32000
disable_tcp_switch=yes
[transport-tcp]
type=transport
protocol=tcp
bind=0.0.0.0:5062
allow_reload=yes
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5062
allow_reload=yes
[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:5063
allow_reload=yes
verify_client=no
verify_server=no
method=tlsv1
[transport-ws]
type=transport
protocol=ws
bind=0.0.0.0:5062
allow_reload=yes
[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:5063
allow_reload=yes

Afterwards, we add the following configurations to the end of the sorcery.conf file under /etc/asterisk/..

[root@localhost ~]# vi /etc/asterisk/sorcery.conf
[res_pjsip]
endpoint=realtime,ps_endpoints
auth=realtime,ps_auths
aor=realtime,ps_aors
domain_alias=realtime,ps_domain_aliases
[res_pjsip_endpoint_identifier_ip]
identify=realtime,ps_endpoint_id_ips

Before restarting Asterisk so it takes into account the changes, we need to make sure that the modules related to Real-Time are loaded correctly on Asterisk.

So, we will add the following modules:
preload => res_odbc.so
preload => res_config_odbc.so
load => func_realtime.so
load => pbx_realtime.so

[root@localhost ~]# vi /etc/asterisk/modules.conf
;
; Asterisk configuration file
;
; Module Loader configuration file
;
[modules]
autoload=yes
preload => res_odbc.so
preload => res_config_odbc.so
load => func_realtime.so
load => pbx_realtime.so

If we desire to work with SIP Devices, it is necessary to comment out the following line:
noload => chan_sip.so

[root@localhost ~]# vi /etc/asterisk/modules.conf
; Do not load chan_sip by default, it may conflict with res_pjsip.
;noload => chan_sip.so

Now, we restart Asterisk and check that the connection is working.

root@localhost ~]# systemctl restart asterisk
[root@localhost ~]# asterisk -rvvvvvvvvvvvv
localhost*CLI> odbc show
ODBC DSN Settings
-----------------
  Name:   asterisk
  DSN:    asterisk
    Number of active connections: 1 (out of 20)
    Logging: Disabled
localhost*CLI>

2.5.- Adding PJSIP and SIP Devices

So now we are going to add some SIP and PJSIP extensions. For which we have to add entries with the data to our Asterisk database created previously.

Add an extension with a PJSIP Device.

[root@localhost ~]# mysql -u root
MariaDB [(none)]> use asterisk;
MariaDB [(asterisk)]> insert into ps_aors (id, max_contacts, qualify_frequency) values (100, 2, 30);
MariaDB [(asterisk)]> insert into ps_auths (id, auth_type, password, username) values (100, 'userpass', 100, 100);100, 100);
MariaDB [(asterisk)]> insert into ps_endpoints (id, transport, aors, auth, context, disallow, allow, direct_media, deny, permit, mailboxes) values (100, 'transport-udp', '100', '100', 'testing', 'all', 'all', 'no', '0.0.0.0/0', '0.0.0.0/0', '100@default');
MariaDB [(asterisk)]> exit;

We repeat these lines with different extension numbers to create new extensions.

To verify that everything is working fine, we perform the following test:

[root@localhost ~]# asterisk -rvvvvvvvvvvvvvvvvvv
localhost*CLI> pjsip show endpoints
Endpoint:  <Endpoint/CID.....................................>    
    I/OAuth:  <AuthId/UserName...........................................................>
        Aor:    
      Contact:  <Aor/ContactUri..........................>   <RTT(ms)..>
  Transport:          
   Identify:  <Identify/Endpoint.........................................................>
        Match:  
    Channel:      
        Exten:   CLCID: 
==========================================================================================
Endpoint:  100                                                  Unavailable   0 of inf
     InAuth:  100/100
        Aor:  100                                                2
  Transport:  transport-udp             udp      0      0  0.0.0.0:5062
Objects found: 1

Up next, we add an extension with a SIP Device.

[root@localhost ~]# mysql -u root
MariaDB [(none)]> use asterisk;
MariaDB [(asterisk)]> insert into sippeers (name, host, type, context, deny, permit, secret, transport, disallow, allow, directmedia, language, mailbox) values (101, 'dynamic', 'friend', 'testing', '0.0.0.0/0', '0.0.0.0/0', 101, 'udp', 'all', 'all', 'nonat', 'en', '101@default');
MariaDB [(astrisk)]> exit;

We repeat these lines with different extension numbers to create new extensions.

To verify that everything is working correctly, we perform the following test:

[root@localhost ~]# asterisk -rvvvvvvvvvvvvvvvvvv
localhost*CLI> sip show peers
Name/username             Host                                    Dyn Forcerport Comedia    ACL Port     Status      Description                      Realtime
0 sip peers [Monitored: 0 online, 0 offline Unmonitored: 0 online, 0 offline]
localhost*CLI>

Most Likely no device will appear, since in the case of SIP, these are not shown until they have registered. For them to be displayed, it is necessary to add the following to the [general] section:
rtcachefriends=yes

[root@localhost ~]# vi /etc/asterisk/sip.conf
[general]
rtcachefriends=yes

2.6.- Adding a Dial Plan

As mentioned in the beginning, this guide is not recommended to be used with the dial plan in a dynamic form. We have also performed various tests, and it does not seem to work properly and Asterisk restarts.

Now that we have at least two extensions added, we would like to make a call between them. For this, we need to create a static Dial Plan which we configure on the extensions.conf file, located under the /etc/asterisk directory.

[root@localhost ~]# vi /etc/asterisk/extensions.conf
[general]
[testing]
exten => 100,1,NoOp(Call Extension ${EXTEN})
 same => n,Dial(PJSIP/${EXTEN},20)
 same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
 same => n(unavail),Voicemail(100@default,u)
 same => n,Hangup()
 same => n(busy),VoiceMail(100@default,b)
 same => n,Hangup()
exten => 101,1,NoOp(Call Extension ${EXTEN})
 same => n,Dial(SIP/${EXTEN},20)
 same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
 same => n(unavail),Voicemail(101@default,u)
 same => n,Hangup()
 same => n(busy),VoiceMail(101@default,b)
 same => n,Hangup()
;Retrieve Voicemail message
exten => *97,1,NoOp(Retrieve VM from Extension ${CALLERID(number)})
 same => n,Answer()
 same => n,VoiceMailMain(${CALLERID(num)}@default)

We restart the Dial Plan

[root@localhost ~]# asterisk -rvvvvvvvvvvvvvvvvvvvv
localhost*CLI> dialplan reload

Congratulations! We can now perform a call between two extensions with Asterisk Real-Time.

2.7.- Adding Voicemail

It is possible that extensions have their own voicemail in Real-Time. To have this option, it is necessary to do the following:

[root@localhost ~]# mysql -u root
MariaDB [(none)]> use asterisk;
MariaDB [(asterisk)]> insert into voicemail (context, mailbox, password, attach, saycid, envelope) values ('default', '100', '100', 'yes', 'yes', 'yes');
MariaDB [(asterisk)]> insert into voicemail (context, mailbox, password, attach, saycid, envelope) values ('default', '101', '101', 'yes', 'yes', 'yes');
MariaDB [(none)]> exit:

2.8.- Adding Queues

Coming up, we will be implementing Queues in Real-Time. These got two components: the first one is the queue parameter, and the second is the static or dynamic agents.

We will add the parameters of the queue table, and a static member. To add static members, we will do it through the Dial Plan.

[root@localhost ~]# mysql -u root
MariaDB [(none)]> use asterisk;
MariaDB [(asterisk)]> insert into queues (name, musiconhold, timeout, ringinuse, queue_holdtime, retry, wrapuptime, strategy) values ('Q500', 'default', '15', 'no', '30', '5', '5', 'ringall');
MariaDB [(asterisk)]> insert into queue_members (queue_name, interface, membername, penalty, wrapuptime) values ('Q500', 'Local/101@testing/n', '101', '0', '5');
MariaDB [(none)]> exit;

We verify all is working properly.

[root@localhost ~]# asterisk -rvvvvvvvvvvvvvvvvvvvvvvv
localhost*CLI> queue show Q500
Q500 has 0 calls (max unlimited) in 'ringall' strategy (0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0%, SL2:0.0% within 0s
   Members:
      101 (Local/101@testing/n) (ringinuse disabled) (realtime) (Not in use) has taken no calls yet
   No Callers
localhost*CLI>exit

Now, we will modify the Dial Plan to be able to call the Queue. We will add the following to the Dial Plan made on section 3.6.

[root@localhost ~]# vi /etc/asterisk/extensions.conf
;Call Queue Q500
exten => 500,1,NoOp(Queue: Testing 500)
 same => n,Playback(queue-youarenext)
 same => n(qconnect),NoOp(Connecting to Queue)
 same => n,Queue(Q500,c,,,30)
 same => n,Hangup()
;Agent Login & Logout
exten => *5001,1,NoOp(Queue: Add Agent ${CALLERID(number)} in Queue 500)
 same => n,AddQueueMember(Q500,Local/${CALLERID(number)}@testing/n,0,,${CALLERID(number)},)
 same => n,Playback(agent-loginok)
exten => *5002,1,NoOp(Queue: Remove Agent ${CALLERID(number} in Queue 500)
 same => n,RemoveQueueMember(Q500,Local/${CALLERID(number)}@testing/n)
 same => n,Playback(agent-loggedoff)

We restart the Dial Plan

[root@localhost ~]# asterisk -rvvvvvvvvvvvvvvvvvvvv
localhost*CLI> dialplan reload

Now we can call from extension 100 to extension 500 and it should give us a message that your call is now the first in line, and afterwards, start ringing on extension 101.

Afterwards, we call from extension 101 to 500, and we will see that it will leave us on queue for 30 seconds and the call will hang up. This is happening due to there not being available agents, and we have a maximum hold time of 30 seconds. If the extension that we are calling to extension 500 has 2 lines, it is possible that it still rings, but we will ignore this for this test.

Now, we will add extension 100 dynamically to the Queue, by dialing *5001 from this extension. And then, we call to the Queue with extension 101, and we will see that extension 100 starts to ring.

To remove extension 100 from the Queue, we just need to dial *5002.

Congratulations! You have just implemented Queues in Real-Time!

We hope that you have enjoyed this implementation of Asterisk Real Time, and if you wish to have more information, you can visit our website, vitalpbx.org.

0

Leave a Reply

Your email address will not be published. Required fields are marked *