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

VitalPBX Asterisk 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 Debian 11 (Bullseye), however, you would be able to use 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 19 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 Debiam 11 NetInst, for which we will start with the installation process of Asterisk 19 and its dependencies. To enter the Debian 11 console, you can start an SSH client, e.g. PuTTY.

2.1.- Install Debian 11 and Update

Install Debian 11.3 and update it to the latest version and some dependence

root@localhost:~# apt update -y
root@localhost:~# apt full-upgrade -y
root@localhost:~# apt -y install build-essential git curl wget libnewt-dev libssl-dev libncurses5-dev subversion libsqlite3-dev libjansson-dev libxml2-dev uuid-dev default-libmysqlclient-dev

2.2.- Firewall Configuration (Optional)

Before installing the firewall, be careful not to block SSH port 22, as you could lose connection to the server.

Debian usually ships without the firewall installed. We recommend installing it and allowing the following ports:.

root@localhost:~# apt 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 19

       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 19

root@localhost:~# cd /usr/src
root@localhost:/usr/src# wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-19-current.tar.gz
root@localhost:/usr/src# tar -zxvf asterisk-19-current.tar.gz
root@localhost:/urs/src# cd asterisk-19.4.1
root@localhost:/urs/src/asterisk-19.4.1# ./contrib/scripts/get_mp3_source.sh
root@localhost:/urs/src/asterisk-19.4.1# contrib/scripts/install_prereq install
root@localhost:/urs/src/asterisk-19.4.1# ./configure --libdir=/usr/lib64 --with-jansson-bundled --with-pjproject-bundled

Then, we proceed to make menuselect

root@localhost:/urs/src/asterisk-19.4.1# 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:/urs/src/asterisk-19.4.1# make && make install
root@localhost:/urs/src/asterisk-19.4.1# make samples
root@localhost:/urs/src/asterisk-19.4.1# make config
root@localhost:/urs/src/asterisk-19.4.1# ldconfig root@localhost:/urs/src/asterisk-19.4.1# chown -R asterisk.asterisk /etc/asterisk root@localhost:/urs/src/asterisk-19.4.1# chown -R asterisk.asterisk /var/{lib,log,spool}/asterisk root@localhost:/urs/src/asterisk-19.4.1# chown -R asterisk.asterisk /usr/lib/asterisk root@localhost:/urs/src/asterisk-19.4.1# systemctl enable asterisk root@localhost:/urs/src/asterisk-19.4.1# systemctl start asterisk root@localhost:/urs/src/asterisk-19.4.1# asterisk -rvvvvvvvvvvvvvvvvvvv Asterisk 19.4.1, Copyright (C) 1999 - 2021, Sangoma Technologies Corporation 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 19.4.1 currently running on vitalpbx (pid = 42979)
vitalpbx*CLI>

Now, to configure Asterisk to run as asterisk user, run the following command:

root@localhost:/urs/src/asterisk-19.4.1# nano /etc/default/asterisk

This will open a file, in the file comment out following two lines:

AST_USER=”asterisk”

AST_GROUP=”asterisk”

The default configuration file used by asterisk is /etc/asterisk/asterisk.conf. You can open the file and see if any change is required.

root@localhost:/urs/src/asterisk-19.4.1# nano /etc/asterisk/asterisk.conf

runuser = asterisk ; The user to run as.
rungroup = asterisk ; The group to run as.

CONGRATULATIONS! You have successfully installed Asterisk 19!

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:/urs/src/asterisk-19.4.1# apt install -y unixodbc odbcinst mariadb-client mariadb-server odbc-mariadb
root@localhost:/urs/src/asterisk-19.4.1# systemctl enable mariadb
root@localhost:/urs/src/asterisk-19.4.1# 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:/urs/src/asterisk-19.4.1# apt install python3-pip -y

Afterwards, we install alembic and some dependency using pip:

root@localhost:/urs/src/asterisk-19.4.1# pip install mysql-connector-python
root@localhost:/urs/src/asterisk-19.4.1# pip install alembic
root@localhost:/urs/src/asterisk-19.4.1# pip install mysqlclient
root@localhost:/urs/src/asterisk-19.4.1# pip install "importlib_metadata==1.5.2"
root@localhost:/urs/src/asterisk-19.4.1# pip install "zipp==1.2.0"
root@localhost:/urs/src/asterisk-19.4.1# pip install "configparser==3.8.1"

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

root@localhost:/urs/src/asterisk-19.4.1# cd /usr/src/asterisk-19.4.1/contrib/ast-db-manage/
root@vitalpbx:/usr/src/asterisk-19.4.1/contrib/ast-db-manage# mv config.ini.sample config.ini
root@vitalpbx:/usr/src/asterisk-19.4.1/contrib/ast-db-manage# nano 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@vitalpbx:/usr/src/asterisk-19.4.1/contrib/ast-db-manage# mysql -u root 
MariaDB [(none)]> create database asterisk;
MariaDB [(none)]> exit;

We create/update the tables with the following command:

root@vitalpbx:/usr/src/asterisk-19.4.1/contrib/ast-db-manage# alembic -c config.ini upgrade head

We enter MariaDB once again:

root@vitalpbx:/usr/src/asterisk-19.4.1/contrib/ast-db-manage# 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:~# nano /etc/odbc.ini
[asterisk]
Description = MySQL Asterisk
Driver = MariaDB Unicode
Database = asterisk
Server = localhost
User = asterisk
Password = asterisk
Port = 3306
Socket = /var/run/mysqld/mysqld.sock
root@localhost:~# nano /etc/odbcinst.ini
[MariaDB Unicode]
Driver=libmaodbc.so
Description=MariaDB Connector/ODBC(Unicode)
Threading=0
UsageCount=1

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:~# nano /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:~# nano /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:~# nano /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:~# nano /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:~# nano /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:~# nano /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:~# nano /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.com.

Our Latest Post