Using XMPP (Jabber) with Asterisk
Using XMPP (Jabber) with Asterisk
The eXtensible Messaging and Presence Protocol (XMPP, formerly called Jabber) is used for instant messaging and communicating presence information across networks in near real time. Within Asterisk, it is also used for call setup (signaling). We can do various cool things with XMPP integration once it’s enabled, such as getting a message whenever someone calls us. We can even send messages back to Asterisk, redirecting our calls to voicemail or some other location. Additionally, with chan_motif , we can accept and place calls over the Google Voice network or accept calls from Google Talk users via the web client.
Compiling XMPP Support into Asterisk
The res_xmpp module contains various dialplan applications and functions that are useful from the Asterisk dialplan. It is also a dependency of the chan_motif channel module. To get started with XMPP integration in Asterisk, we need to compile res_xmpp .
RHEL dependencies
To install res_xmpp , we need the iksemel development library. If the OpenSSL development library is installed, res_xmpp will also utilize that for secure connections (this is recommended). We can install both on RHEL with the following command:
$ sudo yum install iksemel-devel openssl-devel
Ubuntu dependencies
To install res_xmpp , we need the iksemel development library. If the OpenSSL development library is installed, res_xmpp will also utilize that for secure connections (this is recommended). We can install both on Ubuntu with the following command:
$ sudo apt-get install libiksemel-dev libssl-dev
Installing res_xmpp
Once you’ve installed the dependencies, you need to run ./configure in your Asterisk source and make menuselect. Then go into the Resource Modules menu and make sure res_xmpp is enabled. After that, run make install to get the new modules.
Jabber Dialplan Commands
Several dialplan applications and functions can be used for communication using the XMPP protocol via Asterisk. We’re going to explore how to connect Asterisk to an XMPP server, how to send messages to the client from the dialplan, and how to route calls based on responses to the initially sent messages. By sending a message via XMPP, we’re essentially creating a simple screen-pop application to let users know when calls are coming into the system.
Connecting to an XMPP server
Before we can start sending messages to our XMPP buddies, we need to connect to an XMPP-enabled server. We’re going to utilize the XMPP server at Google, as it is open and easily accessible by anyone. To do so, we need to configure the xmpp.conf file in our /etc/asterisk configuration directory. The following example will connect us to the XMPP server at Google.
Our xmpp.conf file should look like this:
[general]
[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
Let’s take a quick look at some of the options we just set so you understand what is going on. The options are described in Table -1. We’ve described all the available options in xmpp.conf even though we haven’t set all options in our example file.
Table -1. xmpp.conf options
After configuring our xmpp.conf file, we can load (or reload) the res_xmpp.so module. We can do this from the console with module reload res_xmpp.so:
*CLI> module reload res_xmpp.so
Reloaded res_xmpp.so
and check the connection with the xmpp show connections command:
*CLI> xmpp show connections
Jabber Users and their status:
User: asterisk@shifteight.org – Connected
—-
Number of users: 1
If you’re having problems getting connected, you can try unloading the module and then loading it back into memory. If you’re still having problems, you can run the xmpp purge nodes command to remove any existing or bad connections from memory. Beyond that, check your configuration and verify that you don’t have any configuration problems or typos. Once you’ve gotten connected, you can move on to the next sections, where the fun starts.
Sending messages with JabberSend()
The JabberSend() dialplan application is used for sending messages to buddies from the Asterisk dialplan. You can use this application in any place that you would normally utilize the dialplan, which makes it quite flexible. We’re going to use it as a screen-pop application for sending a message to a client prior to placing a call to the user’s phone. Depending on the client used, you may be able to have the message pop up on the user’s screen from the task bar. Here is a simple example to get us started:
[LocalSets]
exten => 104,1,Answer()
; *** This line should not have any line breaks
same => n,JabberSend(asterisk,jim@shifteight.org,Incoming call from
${CALLERID(all)})
same => n,Dial(SIP/0000FFFF0002,30)
same => n,Hangup()
This example demonstrates how to use the JabberSend() application to send a message to someone prior to dialing a device. Let’s break down the values we’ve used. The first argument, asterisk , is the section header we defined in the xmpp.conf file as [asterisk] . In our xmpp.conf example, we set up a user called asterisk@shifteight.org to send messages via the Google XMPP server, and asterisk is the section name we defined. The second argument, jim@shifteight.org , is the buddy we’re sending the message to. We can define any buddy here, either as a bare JID (as we’ve done above) or as a full JID with a resource (e.g., jim@shifteight.org/laptop). The third argument to JabberSend() is the message we want to send to the buddy. In this case we’re sending Incoming call from ${CALLERID(all)} , with the CALLERID() dialplan function being used to enter the caller ID information in the message.
Obviously, we would have to further build out our dialplan to make this useful: specifically, we’d have to associate the buddy name (e.g., jim@shifteight.org ) with the device we’re calling ( SIP/0000FFFF0002 ) so that we’re sending the message to the correct buddy. You can save these associations in any one of several locations, such as in the AstDB, in a relational database retrieved with func_odbc , or even in a global variable.
Receiving messages with JABBER_RECEIVE()
The JABBER_RECEIVE() dialplan function allows us to receive responses via XMPP messages, capture those responses, and presumably act on them. We would typically use the JABBER_RECEIVE() function in conjunction with the JabberSend() dialplan
application, as we are likely to need to send a message to someone and prompt him with our /etc/asterisk configuration directory. The following example will connect us to the XMPP server at Google.
Our xmpp.conf file should look like this:
[general]
[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
Let’s take a quick look at some of the options we just set so you understand what is going on. The options are described in Table 18-3. We’ve described all the available options in xmpp.conf even though we haven’t set all options in our example file.
Table -2. xmpp.conf options
After configuring our xmpp.conf file, we can load (or reload) the res_xmpp.so module. We can do this from the console with module reload res_xmpp.so:
*CLI> module reload res_xmpp.so
Reloaded res_xmpp.so
and check the connection with the xmpp show connections command:
*CLI> xmpp show connections
Jabber Users and their status:
User: asterisk@shifteight.org – Connected
—-
Number of users: 1
If you’re having problems getting connected, you can try unloading the module and then loading it back into memory. If you’re still having problems, you can run the xmpp purge nodes command to remove any existing or bad connections from memory. Beyond that, check your configuration and verify that you don’t have any configuration problems or typos. Once you’ve gotten connected, you can move on to the next sections, where the fun starts.
Sending messages with JabberSend()
The JabberSend() dialplan application is used for sending messages to buddies from the Asterisk dialplan. You can use this application in any place that you would normally utilize the dialplan, which makes it quite flexible. We’re going to use it as a screen-pop application for sending a message to a client prior to placing a call to the user’s phone. Depending on the client used, you may be able to have the message pop up on the user’s screen from the task bar.
Here is a simple example to get us started:
[LocalSets]
exten => 104,1,Answer()
; *** This line should not have any line breaks
same => n,JabberSend(asterisk,jim@shifteight.org,Incoming call from
${CALLERID(all)})
same => n,Dial(SIP/0000FFFF0002,30)
same => n,Hangup()
This example demonstrates how to use the JabberSend() application to send a message to someone prior to dialing a device. Let’s break down the values we’ve used. The first argument, asterisk , is the section header we defined in the xmpp.conf file as [asterisk] . In our xmpp.conf example, we set up a user called asterisk@shifteight.org to send messages via the Google XMPP server, and asterisk is the section name we defined. The second argument, jim@shifteight.org , is the buddy we’re sending the message to. We can define any buddy here, either as a bare JID (as we’ve done above) or as a full JID with a resource (e.g., jim@shifteight.org/laptop). The third argument to JabberSend() is the message we want to send to the buddy. In this case we’re sending Incoming call from ${CALLERID(all)} , with the CALLERID() dialplan function being used to enter the caller ID information in the message.
Obviously, we would have to further build out our dialplan to make this useful: specifically, we’d have to associate the buddy name (e.g., jim@shifteight.org ) with the device we’re calling ( SIP/0000FFFF0002 ) so that we’re sending the message to the correct buddy. You can save these associations in any one of several locations, such as in the AstDB, in a relational database retrieved with func_odbc , or even in a global variable.
Receiving messages with JABBER_RECEIVE()
The JABBER_RECEIVE() dialplan function allows us to receive responses via XMPP messages, capture those responses, and presumably act on them. We would typically use the JABBER_RECEIVE() function in conjunction with the JabberSend() dialplan
application, as we are likely to need to send a message to someone and prompt him with the acceptable values he can return. We could use the JABBER_RECEIVE() function either personally, to direct calls to a particular device such as a cell phone or desk phone, or as a text version of an auto attendant to be used when people who are likely to have difficulty hearing the prompts dial in (e.g., users who are deaf or work at noisy job sites). In the latter case, the system would have to be preconfigured to know where to send the messages to, perhaps based on the caller ID of the person calling.
Here is a simple example that sends a message to someone, waits for a response, and then routes the call based on the response:
exten => 106,1,Answer()
; All text must be on a single line.
same => n,JabberSend(asterisk,leif.madsen@gmail.com,Incoming call from
${CALLERID(all)}. Press 1 to route to desk. Press 2 to send to voicemail.)
same => n,Set(JabberResponse=${JABBER_RECEIVE(asterisk,leif@shifteight.org)})
same => n,GotoIf($[“${JabberResponse}” = “1”]?dial,1)
same => n,GotoIf($[“${JabberResponse}” = “2”]?voicemail,1)
same => n,Goto(dial,1)
exten => dial,1,Verbose(2,Calling our desk)
same => n,Dial(SIP/0000FFFF0002,6)
same => n,Goto(voicemail,1)
exten => voicemail,1,Verbose(2,VoiceMail)
; *** This line should not have any line breaks
same => n,Set(VoiceMailStatus=${IF($[${ISNULL(${DIALSTATUS})}
| “${DIALSTATUS}” = “BUSY”]?b:u)})
same => n,Playback(silence/1)
same => n,VoiceMail(100@lmentinc,${VoiceMailStatus})
same => n,Hangup()
Our simple dialplan first sends a message to a Jabber account (leif@shifteight.org) via our systems’ Jabber account ( asterisk ), as configured in xmpp.conf. We then use the JABBER_RECEIVE() dialplan function to wait for a response from leif@shifteight.org. The default timeout is 5 seconds (as defined in xmpp.conf), but you can specify a different timeout with a third argument to JABBER_RECEIVE() . For example, to wait 10 seconds for a response, we could have used a line like this:
Set(JabberResponse=${JABBER_RECEIVE(asterisk,leif@shifteight.org,10)})
Once we’ve either received a response or the timeout has expired, we move on to the next line of the dialplan, which starts checking the response saved to the ${JabberResponse} channel variable. If the value is 1 , we continue our dialplan at dial, 1 of the current context. If the response is 2 , we continue our dialplan at voicemail,1 . If no response (or an unknown response) is received, we continue the dialplan at dial,1 .
The dialplan at dial,1 and voicemail,1 should be fairly self-evident. This is a non- production example; some additional dialplan should be implemented to make the values dynamic.
There is a disadvantage to the way we’ve implemented the JABBER_RECEIVE() function, though. Our function blocks, or waits, for a response from the endpoint. If we set the response value low to minimize delay, we don’t give the recipient much time to respond. However, if we set the response long enough for the recipient to comfortably respond, we cause unnecessary delay in calling a device or sending to voicemail.
We can skirt this issue by using a Local channel. This allows us to execute two sections of dialplan simultaneously, sending a call to the device at the same time we’re waiting for a response from JABBER_RECEIVE() . If we get a response from JABBER_RECEIVE() and we need to do something, we can Answer() the line and cause that section of dialplan to continue. If the device answers the phone, our dialplan with JABBER_RECEIVE() will just be hung up. Let’s take a look at a modified dialplan that implements the Local channel:
exten => 106,1,Verbose(2,Example using the Local channel)
same => n,Dial(Local/xmpp@${CONTEXT}/n&Local/dial@${CONTEXT}/n)
exten => xmpp,1,Verbose(2,Send an XMPP message and expect a response)
; *** This line should not have any line breaks
same => n,JabberSend(asterisk,leif.madsen@gmail.com,Incoming call from
${CALLERID(all)}. Press 2 to send to voicemail.)
same => n,Set(JabberResponse=${
JABBER_RECEIVE(asterisk,leif@shifteight.org,6)})
same => n,GotoIf($[“${JabberResponse}” = “2”]?voicemail,1)
same => n,Hangup()
exten => dial,1,Verbose(2,Calling our desk)
same => n,Dial(SIP/0000FFFF0002,15)
same => n,Goto(voicemail,1)
exten => voicemail,1,Verbose(2,VoiceMail)
same => n,Answer()
; *** This line should not have any line breaks
same => n,Set(VoiceMailStatus=${IF($[${ISNULL(${DIALSTATUS})}
| “${DIALSTATUS}” = “BUSY”]?b:u)})
same => n,Playback(silence/1)
same => n,VoiceMail(100@shifteight,${VoiceMailStatus})
same => n,Hangup()
By adding a Dial() statement at the beginning and shifting our Jabber send and receive functionality into a new extension called xmpp , we ensure that we can simultaneously call the dial extension and the xmpp extension.
Notice that we removed the Answer() application from the first line of the example. The reason for this is because we want to Answer() the line only after a device has answered (which causes the xmpp extension to be hung up); otherwise, we want the voicemail extension to Answer() the line. If the voicemail extension has answered the line, that means either the xmpp extension has received a response and was told to Goto() the voicemail extension, or the Dial() to our device timed out, causing the voicemail extension to be executed, thereby causing the line to be Answer() ed.
With the examples provided here serving as a springboard, you should be able to develop rich applications that send and receive messages via XMPP servers. Some other dialplan applications and functions may help in the development of your application, such as JABBER_STATUS() (or the JabberStatus() dialplan application), which is used for checking on the status of a buddy; the JabberJoin() and JabberLeave() applications, which are used for joining and leaving XMPP conference rooms; and the Jabber SendGroup() application, which allows you to send messages to an XMPP chat room.
chan_motif
The chan_motif module can be used for connecting to Jingle-enabled networks. It sup‐ ports three different transport and protocol derivatives (in order of preference):
• Jingle as defined in the XEP-0166 specification
• Google Jingle, which follows the Jingle specification for the signaling, but uses Google’s custom transport for the media
• Google-V1, the original Google implementation of a preliminary Jingle specification
The channel module is able to automatically determine which transport to use for incoming sessions. For outgoing sessions, it is able to determine the transport automatically if the endpoint being called is in the roster. If the endpoint is not in the roster, then
chan_motif will attempt to connect in the preferred order as listed in the bullet points above until all possibilities have either succeeded or failed.
In our examples we’ll be using Google Talk (GTalk) for placing and receiving calls, since it lets people using Google’s web apps and other tools place calls easily. GTalk is the web-based voice system typically found in the Gmail web interface. Other clients and
add-ons do exist for external applications such as Pidgin, but we’ll be testing with the web-based client from Google.
motif.conf
Once we’re connected via res_xmpp , we can configure the motif.conf file, which defines our connection for receiving and placing calls. A simple configuration file for allowing connections over the Google network (e.g., calls to the web interface embedded in Gmail) looks like the following:
[google]
context=google_incoming
disallow=all
allow=ulaw
connection=asterisk
Seems pretty straightforward, but let’s look at our configuration in some more detail. First, we define the name of our connection, which we’ve called google (the name between the square braces). You could name this anything you want, but this is what we’ll use to reference this account in our dialplan when placing an outbound call. The next line is the context name in our dialplan to which incoming calls will be directed.
We then disable all previously enabled codecs, then enable ulaw for this connection. On the final line, we reference our xmpp.conf file by using the XMPP connection we configured in the previous section. Once we’ve defined our section, we either need to load chan_motif.so (if not previously loaded), or reload it so the channel driver can read in the new configuration information:
*CLI> module reload chan_motif.so
*CLI>– Reloading module ‘chan_motif.so’ (Motif Jingle Channel Driver)
At this point our module has its configuration, and we can move onto configuring the dialplan to allow incoming and outgoing calls.
Accepting calls from Google Talk
To accept calls from Google Talk, we need to add some functionality to our dialplan. First, let’s define the context name in extensions.conf that we configured in motif.conf:
[google_incoming]
After defining our context, we can add an extension for routing the calls. Incoming calls from the Google network will match extension s 6 much like an analog channel coming in via a DAHDI interface. Once the incoming call matches the extension, we can perform any routing we wish, just as with any other incoming call. To make things simple, we’ll direct the call to one of the SIP endpoints we configured previously:
[google_incoming]
exten => s,1,Verbose(2,Incoming call via Google from ${CALLERID(all)})
same => n,Dial(SIP/0000FFFF0001,24)
same => n,Voicemail(100@default,u)
same => n,Hangup()
Of course we can get a little fancier here, and we could perform call screening, redirect to an auto attendant, forward to a cell phone, or whatever other methods we want to employ.
After configuring our dialplan, we just need to run a dialplan reload to make it active. Once done, try calling from another Gmail web interface (not the same account that you’ve configured for your Asterisk system), and your call should be redirected to your SIP endpoint. You can even see that the incoming caller has been added to the buddy list of your Asterisk system:
*CLI> xmpp show buddies
XMPP buddy lists
Client: asterisk
Buddy:
shifteight@gmail.com
Resource: gmail.64F29731
node: http://mail.google.com/xmpp/client/caps
version: 1.1
Google Talk capable: yes
Jingle capable: no
Accepting calls from Google Voice
The configuration for accepting calls from Google Voice is similar (if not identical) to that for Google Talk, which we set up in the preceding section. A little tip, though, is that sometimes you can’t disable the call-screening functionality (for some reason we still got it even when we’d disabled it in the Google Voice control panel). If you run into this problem but don’t want to have to screen your calls, you can automatically send the DTMF prior to ringing your device, by adding the three emphasized lines shown here prior to performing the Dial() :
[google_incoming]
exten => s,1,Verbose(2,Incoming call via Google from ${CALLERID(all)})
same => n,Answer()
same => n,Wait(2)
same => n,SendDTMF(1)
same => n,Dial(SIP/0000FFFF0001,24)
same => n,Voicemail(100@default,u)
same => n,Hangup()
Here, we’re using the Wait() and SendDTMF() applications to first wait 2 seconds after answering the call (which is when the call-screening message will start) and then accept the call automatically (by sending DTMF tones for the number 1). After that, we then send the call off to our device.
Outgoing calls via Google Talk
To place a call to a Google Talk user, configure your dialplan like so:
[LocalSets]
exten => 123,1,Verbose(2,Extension 123 calling shifteight@gmail.com)
same => n,Dial(Motif/google/shifteight@gmail.com,30)
same => n,Hangup()
The Motif/google/shifteight@gmail.com part of the Dial() line can be broken into three parts. The first part, Motif , is the protocol we’re using for placing the outgoing call. The second part, asterisk , is the account name as defined in the motif.conf file. The last part, shifteight@gmail.com , is the location we’re attempting to place a call to.
Outgoing calls via Google Voice
To place calls using Google Voice to PSTN numbers, create a dialplan like the following:
[LocalSets]
exten => _1NXXNXXXXXX,1,Verbose(2,Placing call to ${EXTEN} via Google Voice)
same => n,Dial(Motif/google/${EXTEN}@voice.google.com)
same => n,Hangup()
Let’s discuss the Dial() line briefly, so you understand what is going on. We start with Motif , which is the technology we’ll use to place the call. Following that, we have defined the google user as the connection we’ll use when placing our outgoing call (this is configured in motif.conf). Next is the number we’re attempting to place a call to, as defined by the ${EXTEN} channel variable. We’ve appended @voice.google.com to let the Google servers know this is a call that should be placed through Google Voice 7 as
opposed to another Google Talk user.