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

VitalPBX Asterisk Real Time
Share on facebook
Share on twitter
Share on whatsapp
Share on telegram
Share on linkedin
Share on email
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 18 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

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 18 and its dependencies. To enter the CentOS 7 console, you can start an SSH client, e.g. PuTTY.

2.1.- Install Centos 7 and Update

Install CentOS 7.9 and update it to the latest version and some dependence

[root@localhost ~]# yum update -y
[root@localhost ~]# yum install wget nano epel-release -y

Disable SELINUX on CentOS 7

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

Change the line:

SELINUX=enforcing
to
SELINUX=disabled

[root@localhost ~]# reboot

2.2.- Firewall Configuration

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

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

2.3.- Installing Asterisk 18

       Create the user ‘asterisk’

[root@localhost ~]# groupadd asterisk
[root@localhost ~]# useradd -r -d /var/lib/asterisk -g asterisk asterisk

Now we start the install process of Asterisk 18

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

Then, we proceed to make menuselect

[root@localhost asterisk-18.3.0]# make menuselect

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.

VitalPBX Asterisk Real Time make menuselect

Now we will proceed with the following

[root@localhost asterisk-18.3.0]# make && make install
[root@localhost asterisk-18.3.0]# make samples
[root@localhost asterisk-18.3.0]# make config
[root@localhost asterisk-18.3.0]# chown asterisk. /var/run/asterisk
[root@localhost asterisk-18.3.0]# chown asterisk. -R /etc/asterisk
[root@localhost asterisk-18.3.0]# chown asterisk. -R /var/{lib,log,spool}/asterisk
[root@localhost asterisk-18.3.0]# chkconfig asterisk on
[root@localhost asterisk-18.3.0]# systemctl start asterisk
[root@localhost asterisk-18.3.0]# asterisk -rvvvvvvvvvvvvvvvvvvv
Asterisk 18.3.0, Copyright (C) 1999 - 2021, 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 18.3.0 currently running on localhost (pid = 91658)
localhost*CLI>

CONGRATULATIONS! You have successfully installed Asterisk 18!

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 and some dependency using pip:

[root@localhost ~]# pip install alembic
[root@localhost ~]# pip install "importlib_metadata==1.5.2"
[root@localhost ~]# pip install "zipp==1.2.0"
[root@localhost ~]# pip install "configparser==3.8.1"

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

[root@localhost ~]# cd /usr/src/asterisk-18.3.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-18.3.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;

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:5060 allow_reload=yes
[transport-udp] type=transport protocol=udp bind=0.0.0.0:5060 allow_reload=yes
[transport-tls] type=transport protocol=tls bind=0.0.0.0:5061 allow_reload=yes verify_client=no verify_server=no method=tlsv1
[transport-ws] type=transport protocol=ws bind=0.0.0.0:5060 allow_reload=yes
[transport-wss] type=transport protocol=wss bind=0.0.0.0:5061 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

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 Devices

So now we are going to add some 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); 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', 'ulaw,alaw,gsm', 'no', '0.0.0.0/0', '0.0.0.0/0', '100@default');

MariaDB [(asterisk)]> insert into ps_aors (id, max_contacts, qualify_frequency) values (101, 2, 30);
MariaDB [(asterisk)]> insert into ps_auths (id, auth_type, password, username) values (101, 'userpass', 101, 101);
MariaDB [(asterisk)]> insert into ps_endpoints (id, transport, aors, auth, context, disallow, allow, direct_media, deny, permit, mailboxes) values (101, 'transport-udp', '101', '101', 'testing', 'all', 'ulaw,alaw,gsm', 'no', '0.0.0.0/0', '0.0.0.0/0', '101@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:5060

Endpoint: 101 Unavailable 0 of inf
InAuth: 101/101
Aor: 101 2
Transport: transport-udp udp 0 0 0.0.0.0:5060 Objects found: 2

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 => _1XX,1,NoOp()
same => n,Dial(${PJSIP_DIAL_CONTACTS(${EXTEN})})
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
same => n(unavail),Voicemail(${EXTEN}@default,u)
same => n,Hangup()
same => n(busy),VoiceMail(${EXTEN}@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.

Our Latest Post

No comment yet, add your voice below!


Add a Comment

66 West Flagler Street
Suite 900 – #1957
Miami, FL 33130, USA

Phone: +1(305) 560-5776
Email: sales@vitalpbx.org

SUBSCRIBE

Subscribe to our newsletter to receive updates and the latest news from VitalPBX

Copyright @ 2020 VitalPBX,  All rights reserved.