The eXtensible Messaging and Presence Protocol (XMPP)
(formerly called Jabber) is used for instant messaging and communicating
presence information across networks in near-realtime. Within Asterisk, it
is also used for call setup (signaling). There are various cool things we
can do 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_gtalk
, we can accept and
place calls over the Google Voice network or accept calls from Google Talk
users via the web client.
The res_jabber
module
contains various dialplan applications and functions that are useful
from the Asterisk dialplan. It is also a dependency of the chan_gtalk
and chan_jingle
channel modules. To get started
with XMPP integration in Asterisk, we need to compile res_jabber
.
To install res_jabber
, we need the iksemel
development library (http://code.google.com/p/iksemel/). If the OpenSSL
development library is installed, res_jabber
will also utilize that for secure
connections (this is recommended). We can install both on CentOS with
the following command:
$ sudo yum install iksemel-devel openssl-devel
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 to the system.
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 jabber.conf
file in our /etc/asterisk/
configuration directory. The
following example will connect us to the XMPP server at Google.
You must already have a Gmail account, which you can get at http://www.gmail.com.
Our jabber.conf
file should look like
this:
[general] debug=no autoprune=no autoregister=yes auth_policy=accept [asterisk] type=client serverhost=talk.google.com
username=asterisk@shifteight.org
secret=<super_secret_password>
port=5222 usetls=yes usesasl=yes status=available statusmessage="Ohai from Asterisk"
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, “jabber.conf options”. Note that the first four
options are set in the [general]
section, and the others are set in the peer section.
Table 18.3. jabber.conf options
After configuring our jabber.conf
file, we can load (or reload)
the res_jabber.so
module. We can
do this from the console with jabber
reload:
*CLI> jabber reload
Jabber Reloaded.
and check the connection with the jabber show connections command:
*CLI>
jabber 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 jabber 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.
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 jabber.conf
file as
[asterisk]
. In
our jabber.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
Jabber
Send()
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 the in AstDB, in
a relational database retrieved with func_odbc
, or even in a global
variable.
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()
Unfortunately, the JabberSend()
application requires all of
the message to be sent on a single line. If you wish to break up
the text onto multiple lines, you will need to send it as multiple
messages on separate lines using JabberSend()
.
Our simple dialplan first sends a message to a Jabber account
(leif@shifteight.org) via our systems’ Jabber
account (asterisk
), as configured
in jabber.conf
. We then use the
JABBER_RECEIVE()
dialplan function
to wait for a response from leif@shifteight.org
. The default timeout is
5 seconds, 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 ${Jabber
Response}
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 user we
sent the message to much time to respond. However, if we set the
response long enough to make it comfortable for the user to send a
response, we cause unnecessary delay in calling a device or sending to
voicemail.
We can skirt around 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/jabber@${CONTEXT}/n&Local/dial@${CONTEXT}/n)
exten => jabber,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@lmentinc,${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 jabber
, we ensure that we can simultaneously
call the dial
extension and the
jabber
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 jabber
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 jabber
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 make use of sending and receiving messages via XMPP
servers. Some other dialplan applications and functions exist that 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 JabberSendGroup()
application, which allows
you to send messages to an XMPP chat room.
The chan_gtalk
module
can be used for connecting to Google Talk (GTalk) clients or for sending
and receiving calls via the Google Voice network, which is a PSTN-connected network where you can purchase
minutes just like you would from any other ITSP. GTalk is the web-based
voice system typically found in GMail web interfaces. Other clients and
addons do exist for external applications such as Pidgin, but we’ll be
testing with the web-based client from Google.
Before we can get connected to
chan_gtalk
, we need to make sure
we’re connected via res_jabber
, so if
you haven’t already done so, review the section called “Connecting to an XMPP server” for information about how to
connect to the Google XMPP servers.
Once we’re connected via res_jabber
, we can configure the gtalk.conf
file, which is used for
accepting incoming calls from the Google network. The following
configuration enables the guest account, which is required to accept
incoming calls. There is currently no support for authenticating
incoming calls and then separating and sending them to different
contexts, which you may be used to from the configuration of other
channel drivers in Asterisk. For now chan_gtalk
is fairly simple, but future
versions of Asterisk may add this feature.
Our gtalk.conf
file looks
like this:
[general] bindaddr=0.0.0.0 ; Address to bind to allowguests=yes ; Allow calls from people not in contact list ; Optional arguments ; externip=<external IP of server>
; stunaddr=<stun.yourdomain.tld
> [guest] ; special account for options on guest account disallow=all allow=ulaw context=gtalk_incoming connection=asterisk ; connection name defined in jabber.conf
If
your Asterisk system lives behind NAT, you may need to add some
additional options to the [general]
section in order to place the correct IP address into the headers. If
you have a static external IP address, you can use the externip
option to specify it.
Alternatively, you could use the stunaddr
option to specify the address of
your STUN server, which will then look up your address from an
external server and place that information into the headers.
If you configure the stunaddr
option in gtalk.conf
and
the lookup is successful, it will override any value specified in
the externip
option.
Let’s discuss briefly the options
we’ve configured in gtalk.conf
.
In the [general]
section, we have
set the bindaddr
option to 0.0.0.0
, which means to listen on all
interfaces.[160] You can also specify a single interface to listen on by
specifying the IP address of that interface. The next line is allowguests
, which can be set to either
yes
or no
but is only useful when set to yes
. Because the module does not offer the
ability to specify different control mechanisms for different users,
all users are treated as guests.[161]
Next we’ve specified the [guest]
account, which will let us accept
calls from Google Voice and Google Talk users. This account is only
used for incoming calls. When placing outgoing calls, we’ll use the
account specified in the jabber.conf
file. Within the [guest]
account, we’ve disabled all codecs
with the disallow=all
option, and
then specifically enabled the ulaw codec with allow=ulaw
on the following line. Incoming
calls are then directed to the gtalk_incoming
context with the context
option. We specify which account calls will be
coming from with the connection
option, which we’ve set to the account created in jabber.conf
.
The chan_gtalk
module does not support reloading
the configuration. If you change the configuration, you will have to
either restart Asterisk or unload and reload the module, which can
only be done when no GTalk calls are up. You can do that using the
following commands:
*CLI>
module unload chan_gtalk.so
*CLI>
module load chan_gtalk.so
To allow calls from other Google Talk users, we need to
configure our dialplan to accept incoming calls. Inside your extensions.conf
file, add the [gtalk_incoming]
context:
[gtalk_incoming] exten => s,1,Verbose(2,Incoming Gtalk call from ${CALLERID(all)}) same => n,Answer() same => n,Dial(SIP/0000FFFF0001,30) same => n,Hangup()
We’ve now configured a simple test
dialplan that will send calls to the SIP/0000FFFF0001
device and wait 30 seconds
before hanging up the line. The s
extension can be used to match any incoming call from Google Talk or
Google Voice, but if you have multiple accounts that could be coming
into this context, you can match different users by specifying the
username portion of the Gmail email address as the extension. So, for
example, if we had a user
my_asterisk_user@gmail.com, the username portion
would be my_asterisk_user
, and this
is what we’d specify in [gtalk_incoming]
:
[gtalk_incoming] exten => my_asterisk_user,1,Verbose(2,Gtalk call from ${CALLERID(all)}) same => n,Answer() same => n,Dial(SIP/0000FFFF0001,3) same => n,Hangup()
The order of rules used for matching
incoming calls to chan_gtalk
is:
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 two boldface lines shown here prior to performing
the Dial()
:
[gtalk_incoming]
exten => s,1,Verbose(2,Incoming call from ${CALLERID(all)})
same => n,Answer()
same => n,Wait(2)
same => n,SendDTMF(2)
same => n,Dial(SIP/0000FFFF0001,30)
same => n,Hangup()
Here, we’re using the Wait()
and SendDTMF()
applications to first wait 2
seconds after answering the call (which is the time when the call
screening message will start) and then accept the call automatically
(by sending DTMF tones for the number 2). After that, we then send the
call off to our device.
To place a call to a Google Talk user, configure your dialplan like so:
[LocalSets] exten => 123,1,Verbose(2,Extension 123 calling some_user@gmail.com) same => n,Dial(Gtalk/asterisk/some_user@gmail.com,30) same => n,Hangup()
The Gtalk/asterisk/some_user@gmail.com
part of
the Dial()
line can be broken into
three parts. The first part, Gtalk
,
is the protocol we’re using for placing the outgoing call. The second
part, asterisk
, is the account name
as defined in the jabber.conf
file. The last part, some_user@gmail.com
, is the location we’re
attempting to place a call to.
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(Gtalk/asterisk/+${EXTEN}@voice.google.com) same => n,Hangup()
Let’s discuss the Dial()
line briefly, so you understand what
is going on. We start with Gtalk
,
which is the technology we’ll use to place the call. Following that,
we have defined the asterisk
user
as the account we’ll use to authenticate with when placing our
outgoing call (this is configured in jabber.conf
). Next is the number we’re
attempting to place a call to, as defined in the ${EXTEN}
channel variable. We’ve prefixed
the ${EXTEN}
channel variable with a plus sign (+
), as it’s required by the Google network
when placing calls. We’ve also appended @voice.google.com
to let the Google servers
know this is a call that should be placed through Google
Voice[162] as opposed to to another Google Talk user.