Out-of-Band Messaging (Messaging Infrastructure)
Out-of-Band Messaging (Messaging Infrastructure)
Starting in Asterisk 10, the ability to accept messages out of band (e.g., receive a message without an existing channel) was added in order to allow the triggering of the dialplan based on a received message. Being able to accept a message means that you could potentially trigger a call simply by sending a message to dialplan from your XMPP client. As you can imagine, many possibilities exist for this, including being able to provide menu options in advance of a call, looking up people in a directory, or getting information about a company without ever placing a call to the system. And once someone was ready to receive a call, they could request the system to call them and connect them with an agent.
The messaging infrastructure allows both receiving and sending messages through either SIP or XMPP using a combination of the MESSAGE() dialplan function, the Messa geSend() dialplan application, and the configuration of either (or both) sip.conf and xmpp.conf to direct incoming calls to an appropriate location in the dialplan.
xmpp.conf Configuration
We’ll assume you’ve already configured the xmpp.conf file per “Using XMPP (Jabber) with Asterisk” so we’ll skip over the initial configuration. The only thing you need to do in order to accept messages via XMPP is to add two configuration options, described in Table 1, to the [asterisk] account you created.
Table 1. Options related to out-of-band messaging with XMPP
Setting sendtodialplan of either no (default) or yes will control whether incoming messages to this XMPP user will be sent to the dialplan. Which dialplan context will parse the messages is controlled with the context setting. Our configuration in xmpp.conf would look like:
[asterisk]
type=client
serverhost=talk.google.com
username=asterisk@shifteight.org
secret=<super_secret_password>
priority=1
port=5222
usetls=yes
usesasl=yes
status=available
statusmessage=”Ohai from Asterisk”
timeout=5
sendtodialplan=yes
contexts=IncomingMessages
After updating your configuration in xmpp.conf, you can reload the res_xmpp.so module in Asterisk:
$ asterisk -rx “module reload res_xmpp.so”
sip.conf Configuration
Asterisk has an initial implementation of SIP messaging. The functionality is very basic in that it only supports the MESSAGE SIP method. Session-oriented messaging using a Message Session Relay Protocol (MSRP) session is not supported. Unfortunately, SIP
clients typically support only session-oriented messaging. Since this isn’t part of Asterisk, messaging over SIP is most useful between Asterisk boxes themselves.
Enabling messaging support is quite straightforward. There are three options (described in Table 2) associated with messaging, two of which are already enabled by default.
Table 2. Options related to out-of-band messaging in SIP
Instead of relying on the default settings in Asterisk, we’ll define all three options in the [general] section of our sip.conf file. This way we can see explicitly what we’ve enabled:
; Out of band messaging
accept_outofcall_message=yes
outofcall_message_context=IncomingMessages
auth_message_requests=yes
Once configured, reload the SIP channel driver:
$ asterisk -rx “sip reload”
Dialplan Configuration
In this section, we’ll demonstrate how to configure the dialplan to receive and send messages over the XMPP protocol.
After we’ve configured our system as described in “xmpp.conf Configuration” in previous post, we need to configure our dialplan to handle incoming messages. First, let’s configure the dialplan so we can accept a message and display it to the Asterisk console:
[IncomingMessages]
exten => s,1,NoOp()
same => n,Verbose(2,Totally getting a message yo)
same => n,Verbose(2,Got message from ${MESSAGE(from)} destined for
${MESSAGE(to)} with body ${MESSAGE(body)}))
As you can see, we’ve defined our context IncomingMessages . When a message is bound for Asterisk, it will get matched in the context by the s extension. At our first priority we simply execute a NoOp() . The next line outputs some standard text using the Ver
bose() application. On the last line, we use the Verbose() application again to show the contents of the message body, and who the message came from, and who it was destined to. The contents of the message body and the from and to headers are displayed using the MESSAGE() function, which is used for both displaying received data (as we’ve shown), and for sending data from our Asterisk system.
To test this dialplan example, type the following:
$ asterisk -r
*CLI> dialplan reload
*CLI> core set verbose 5
Now we send an XMPP message to the Asterisk server after adding our PBX to our buddy list. After sending any message, we should see the Verbose() output on our console. If not, we verify our connection with xmpp show connections and make sure the user messaging the PBX is listed in xmpp show buddies . To send a response, we use the MESSAGE() function to define the body of the message, and the MessageSend() application to trigger the response being sent to the far end. We simply add the following two lines after what’s already been defined in extensions.conf:
same => n,Set(MESSAGE(body)=Thank you for messaging the Shift-Eight PBX)
same => n,MessageSend(${MESSAGE(from)},XMPP:asterisk)
Let’s review what we’re doing. The first line defines the message body that we’ll respond with to an incoming message. You can’t define multiple lines here, or have any new lines in the message body. The second line is what passes the message body back to the
endpoints we received a message from. The arguments to MessageSend() are who to respond to, and what account to use for responding. Looking at our second line, our first argument uses the MESSAGE() function with the from argument, which will cause the message to be sent to the same endpoint that we received a message from. The second argument is a combination of the protocol to respond over ( XMPP in this case, the other option is SIP) and the account name as defined in xmpp.conf (asterisk).
After making your changes, reload the dialplan with dialplan reload and send a message to the PBX. You should now get a response thanking you for messaging the Shift-Eight PBX.
LDAP Integration
Asterisk supports the ability to connect to an existing Lightweight Directory Access Protocol (LDAP) server to load information into your Asterisk server using the Asterisk Realtime Architecture (ARA). The advantage of integrating Asterisk and LDAP will become immediately obvious when you start centralizing your authentication mechanisms to the LDAP server and using it for several applications: you significantly cut down the administrative overhead of managing your users by placing all their information in a central location.
There are both commercial and open source LDAP servers available, the most popular commercial solution likely being the one implemented by Microsoft Windows servers. A popular open source LDAP server is OpenLDAP. We will not delve into the configuration of the LDAP server here, but we will show you the schema required to connect Asterisk to your server and to use it to provide SIP connections and voicemail service to your existing user base.
Configuring OpenLDAP
While a discussion of the installation and configuration of an LDAP server is beyond the scope of this chapter, it is certainly applicable to show you how we expanded our initial LDAP schema to include the information required for Asterisk integration. Our initial installation followed instructions from the Ubuntu documentation page. We only needed to follow the instructions up to and including the backend.example.com.ldif import; the next step after importing the backend configuration is installing the Asterisk-related schemas.
If you’re following along, with the backend imported, change into your Asterisk source directory. Then copy the asterisk.ldap-schema file into the /etc/ldap/schema directory:
$ cd ~/src/asterisk-complete/asterisk/11/contrib/scripts/
$ sudo cp asterisk.ldap-schema /etc/ldap/schema/asterisk.schema
With the schema file copied in, restart the OpenLDAP server:
$ sudo /etc/init.d/slapd restart
Now we’re ready to import the contents of asterisk.ldif into our OpenLDAP server. Theasterisk.ldif file is located in the /contrib/scripts folder of the Asterisk source directory:
$ sudo ldapadd -Y EXTERNAL -H ldapi:/// -f asterisk.ldif
We can now continue with the online instructions and import the frontend.example.com.ldif file. Within that file is an initial user, which we can omit for now as we’re going to modify the user import portion to include an objectClass for Asterisk (i.e., in the example file, the section of text that starts with uid=john can be deleted). We’ll create a user and add the configuration values that will let the user register his phone (which will likely be a softphone, since the hardphone on the user’s desk will, in most cases, be configured from a central location) via SIP by using his username and password, just as he would normally log in to check email and such.
The configuration file we’ll create next will get imported with the ldapadd command and will be added into the people object unit within the shifteight.org space. Be sure to change the values to match those of the user you wish to set up in LDAP and to substitute
dc=shifteight,dc=org with your own location.
Before we create our file, though, we need to convert the password into an MD5 hash. Asterisk will not authenticate phones using plain-text passwords when connecting via LDAP. We can convert the password using the md5sum command:
$ echo “my_secret_password” | md5sum
a7be810a28ca1fc0668effb4ea982e58 –
We’ll insert the returned value (without the hyphen) into the following file within the userPassword field, prefixed with {md5} :
$ cat > astuser.ldif
dn: uid=rbryant,ou=people,dc=shifteight,dc=org
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
objectClass: AsteriskSIPUser
uid: rbryant
sn: Bryant
givenName: Russell
cn: RussellBryant
displayName: Russell Bryant
uidNumber: 1001
gidNumber: 10001
userPassword: {md5}a7be810a28ca1fc0668effb4ea982e58
gecos: Russell Bryant
loginShell: /bin/bash
homeDirectory: /home/russell
shadowExpire: -1
shadowFlag: 0
shadowWarning: 7
shadowMin: 8
shadowMax: 999999
shadowLastChange: 10877
mail: russell.bryant@shifteight.org
postalCode: 31000
l: Huntsville
o: shifteight
title: Asterisk User
postalAddress:
initials: RB
AstAccountCallerID: Russell Bryant
AstAccountContext: LocalSets
AstAccountDTMFMode: rfc2833
AstAccountMailbox: 101@shifteight
AstAccountNAT: yes
AstAccountQualify: yes
AstAccountType: friend
AstAccountDisallowedCodec: all
AstAccountAllowedCodec: ulaw
AstAccountMusicOnHold: default
With the file created, we can add the user to our LDAP server:
$ sudo ldapadd -x -D cn=admin,dc=shifteight,dc=org -f astusers.ldif -W
Enter LDAP Password:
adding new entry “uid=rbryant,ou=people,dc=shifteight,dc=org”
Our user has now been imported into LDAP. The next step is to configure Asterisk to connect to the LDAP server and allow users to authenticate and register their phones.
Compiling LDAP Support into Asterisk
With our OpenLDAP server configured and the schema imported, we need to install the dependencies for Asterisk and compile the res_config_ldap module. This module is the key that will allow us to configure Asterisk realtime for accessing our peers via LDAP. Once we’ve installed the dependency, we need to rerun the ./configure script inside the Asterisk source directory, then verify that the res_config_ldap module is selected. Then we can run make install to compile and install the new module. Ubuntu dependencies
On Ubuntu, we need to install the openldap-dev package to provide the dependency for the res_config_ldap module:
$ sudo apt-get install openldap-dev
RHEL dependencies On RHEL, we need to install the openldap-devel package to provide the dependency for the res_config_ldap module:
$ sudo yum install openldap-devel
Configuring Asterisk for LDAP Support
Now that we’ve configured our LDAP server and installed the res_config_ldap module, we need to configure Asterisk to support loading of peers from LDAP. To do this, we need to configure the res_ldap.conf file to connect to the LDAP server, and the extconfig.conf file to tell Asterisk what information to get from the LDAP server andhow. Once that is done, we can configure any remaining module configuration files, such as sip.conf, iax.conf, voicemail.conf, and so on, where appropriate. In our example, we’ll be configuring Asterisk to load our SIP peers from realtime using the LDAP server as our database.
Configuring res_ldap.conf
The res_ldap.conf.sample file is a good place to start because it contains a good set of templates. At the top of the file, though, under the [_general] section, we need to configure how Asterisk is going to connect to our LDAP server. Our first option is url , which will determine how to connect to the server. We have defined a connection as ldap://172.16.0.103:389 , which will connect to the LDAP server at IP address 172.16.0.103 on port 389 . If you have a secure connection to your LDAP server, you can replace ldap:// with ldaps:// . Additionally, we have set protocol=3 to state that we’re connecting with protocol version 3, which in most (if not all) cases will be correct.
The last three options, basedn , user , and pass , are used for authenticating to our LDAP server. We need to specify:
• The basedn ( dc=shifteight,dc=org ), which is essentially our domain name
• The user name we’re going to authenticate to the LDAP server as ( admin )
• The password for the user to authenticate with ( canada )
If we put it all together, we end up with something like the following:
[_general]
url=ldap://172.16.0.103:389
protocol=3
basedn=dc=shifteight,dc=org
user=cn=admin,dc=shifteight,dc=org
pass=canada
Beyond this, in the rest of the sample configuration file we’ll see lots of templates we can use for mapping the information in Asterisk onto our LDAP schema. Let’s take amlook at the first lines of the [sip] template that we’ll be using to map the information of our SIP peers into the LDAP database:
[sip]
name = cn
amaflags = AstAccountAMAFlags
callgroup = AstAccountCallGroup
callerid = AstAccountCallerID
…
lastms = AstAccountLastQualifyMilliseconds
useragent = AstAccountUserAgent
additionalFilter=(objectClass=AsteriskSIPUser)
On the left side, we have the field name Asterisk will be looking up, and on the right is the mapping to the LDAP schema for the request. Our first set of fields is mapping the name field to the cn field on the LDAP server. If you look back at the data we imported in “Configuring OpenLDAP” you’ll see that we have created a user and assigned the value of RussellBryant to the cn field. So, in this case, we’re mapping the authentication name (the name field) from the SIP user to the value of the cn field in the
LDAP server ( RussellBryant ). This goes for the rest of the values all the way down, with some fields (i.e., useragent , lastms , ipaddr ) simply needing to exist so Asterisk can write information (e.g., registration information) to the LDAP server.
Configuring extconfig.conf
Our next step is to tell Asterisk what information to load via realtime and what technology to use. Using the extconfig.conf file, we have the option of loading several modules dynamically (and we can also load files statically). For more information about Asterisk
realtime, see “Using Realtime” . For our example, we’re going to configure the sipusers and sippeers dynamic realtime objects to load our SIP peers from LDAP. In the following example, we have a line like this:
ldap,”ou=people,dc=shifteight,dc=org”,sip
We’ve specified three arguments. The first is ldap , which is the technology we’re going to use to connect to our realtime object. There are other technologies available, such as odbc , pgsql , curl , and so on. Our second argument, enclosed in double quotes, specifies which database we’re connecting to. In the case of LDAP, we’re connecting to the object-unit people within the domain shifteight.org . Lastly, our third argument, sip , defines which template we’re using (as defined in res_ldap.conf) to map the realtime data to the LDAP database.
To define the use of sipusers and sippeers from the LDAP server, we would enable these lines in extconfig.conf:
sipusers => ldap,”ou=people,dc=shifteight,dc=org”,sip
sippeers => ldap,”ou=people,dc=shifteight,dc=org”,sip
Configuring sip.conf for realtime
These steps are optional for configuring SIP for realtime, although you will likely expect things to work in the manner we’re going to describe. In the sip.conf file, we will enable a few realtime options that will cache information into memory as it is loaded from the database. By doing this, we’ll allow Asterisk to place calls to devices by simply looking at the information stored in memory. Not only does caching make realtime potentially more efficient, but things like device-state updates simply can’t work unless the devices are cached in memory.
To enable peer caching in Asterisk, use the rtcachefriends option in sip.conf:
rtcachefriends=yes
There are additional realtime options as well, such as rtsavesysname , rtupdate , rtau toclear , and ignoreregexpire . These are all explained in the sip.conf.sample file located within your Asterisk source.
Text-to-Speech Utilities
Text-to-speech utilities are used to convert strings of words into audio that can be played to your callers. Text-to-speech has been around for many years, and has been continually improving. While we can’t recommend text-to-speech utilities to take the place of professionally recorded prompts, they do offer some degree of usefulness in applications where dynamic data needs to be communicated to a caller.
Festival
Festival is one of the oldest running applications for text-to-speech on Linux. While the quality of Festival is not sufficient for us to recommend it for production use, it is certainly a useful way of testing a text-to-speech-based application. If a more polished sound is required for your application, we recommend you look at Cepstral (covered
next).
Installing Festival on RHEL
Installing Festival and its dependencies on RHEL is straightforward. Simply use yum to
install the festival package:
$ sudo yum install festival
Installing Festival on Ubuntu
To install Festival and its dependencies on Ubuntu, simply use apt-get to install the festival package:
$ sudo apt-get install festival
Using Festival with Asterisk
With Festival installed, we need to modify the festival.scm file in order to enable Asterisk to connect to the Festival server. On both RHEL and Ubuntu, the file is located in /usr/share/festival. Open the file and place the following text just above the last line, (provide’festival) :
(define (tts_textasterisk string mode)
“(tts_textasterisk STRING MODE)
Apply tts to STRING. This function is specifically designed for
use in server mode so a single function call may synthesize the string.
This function name may be added to the server safe functions.”
(let ((wholeutt (utt.synth (eval (list ‘Utterance ‘Text string)))))
(utt.wave.resample wholeutt 8000)
(utt.wave.rescale wholeutt 5)
(utt.send.wave.client wholeutt)))
After adding that, you need to start the Festival server:
$ sudo festival_server 2>&1 > /dev/null &
Using menuselect from your Asterisk source directory, verify that the app_festival application has been selected under the Applications heading. If it was not already selected, be sure to run make install after selecting it to install the Festival() dialplan application.
Before you can use the Festival() application, you need to tell Asterisk how to connect to the Festival server. The festival.conf file is used to control how Asterisk connects to and interacts with the Festival server. The sample festival.conf file located in the Asterisk source directory is a good place to start, so copy festival.conf.sample from the /configs subdirectory of your Asterisk source to the /etc/asterisk configuration directory now:
$ cp ~/asterisk-complete/asterisk/11/configs/festival.conf.sample /etc/asterisk/festival.conf
The default configuration is typically enough to connect to the Festival server running on the local machine, but you can optionally configure parameters such as the host where the Festival server is running (if remote), the port to connect to, whether to enable caching of files (defaults to no ), the location of the cache directory (defaults to /tmp), and the command Asterisk passes to the Festival server. You can verify that the Festival() dialplan application is accessible by running core
show application festival from the Asterisk console:
*CLI> core show application festival
If you don’t get output, you may need to load the app_festival.so module:
*CLI> module load app_festival.so
Verify that the app_festival.so module exists in /usr/lib/asterisk/modules if you’re still having issues with loading the module.
After loading the Festival() application into Asterisk, you need to create a test dialplan
extension to verify that Festival() is working:
[LocalSets]
exten => 203,1,Verbose(2,This is a Festival test)
same => n,Answer()
same => n,Playback(silence/1)
same => n,Festival(Hello World)
same => n,Hangup()
Reload the dialplan with the dialplan reload command from the Asterisk console, and test out the connection to Festival by dialing extension 203 .
Alternatively, if you’re having issues with the Festival server, you could use the following method to generate files with the text2wave application supplied with the festival package:
exten => 202,1,Verbose(2,Trying out Festival)
same => n,Answer()
; *** This line should not have any line breaks
same => n,System(echo “This is a test of Festival”
| /usr/bin/text2wave -scale 1.5 -F 8000 -o /tmp/festival.wav)
same => n,Playback(/tmp/festival)
same => n,System(rm -f /tmp/festival.wav)
same => n,Hangup()
You should now have enough to get started with generating text-to-speech audio for your Asterisk system. The audio quality is not brilliant, and the speech generated is not clear enough to be easily understood over a telephone, but for development and testing purposes Festival can fill the gap until you’re ready for a more professional-sounding text-to-speech generator such as Cepstral.
Cepstral
Cepstral is a text-to-speech engine that works in a similar manner as the Festival() application in the dialplan, but it produces much higher-quality sound. Not only is the quality significantly better, but Cepstral has developed a text-to-speech engine that emulates Allison’s voice, so your text-to-speech engine can sound the same as the English sound files that ship with Asterisk by default, to give a consistent experience to the caller. Cepstral is a commercial module, but for around $30 you can have a text-to-speech engine that is clearer, is more consistent with other sound prompts on your system, and provides a more pleasurable experience for your callers. The Cepstral software and installation instructions can be downloaded from the Digium.com webstore.