
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
- 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.
- On this guide we are using CentOS 7, however, you would be able to use CentOS 8 or Ubuntu if you so desire.
- 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.
- 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.
Hi, thank you for the instructions, I have followed the steps but my registrations failing with the following. Any suggestions what to check ?
chan_sip.c:29050 handle_request_register: Registration from ” failed for ‘92.2.222.9:14442’ – Wrong password
In the example pjsip is used, so you must use port 5062 to register the extension
Hi Rodrigo,
Thanks and I have managed to pass that point and it was due to config. I use pjsip and mariadb on ubuntu.
Now I get this error for 100. However, if I use 501 it can regiter ok … Could be it an issue with db records ?
[Oct 10 16:03:08] NOTICE[4626]: acl.c:784 ast_apply_acl_internal: SIP ACL: Rejecting ‘x.x.x.x’ due to a failure to pass ACL ‘(BASELINE)’
[Oct 10 16:03:08] NOTICE[4626]: res_pjsip/pjsip_distributor.c:676 log_failed_request: Request ‘REGISTER’ from ” failed for ‘x.x.x.x:10084’ (callid: 26e4303127390280674471k3161rmwp) – Not match Endpoint ACL
[Oct 10 16:03:08] NOTICE[4626]: res_pjsip/pjsip_distributor.c:676 log_failed_request: Request ‘REGISTER’ from ” failed for ‘x.x.x.x:10084’ (callid: 26e4303127390280674471k3161rmwp) – Failed to authenticate
insert into ps_aors (id, max_contacts) values (501, 1);
insert into ps_auths (id, auth_type, password, username) values (502, ‘userpass’, 1234, 502);
insert into ps_endpoints (id, transport, aors, auth, context, disallow, allow, direct_media) values (501, ‘transport-udp’, ‘501’, ‘501’, ‘testing’, ‘all’, ‘g722’, ‘no’);
Check this:
insert into ps_auths (id, auth_type, password, username) values (502, ‘userpass’, 1234, 502);
You configured extension 502 instead of 501