People who think they know everything are a great annoyance to those of us who do.
Isaac Asimov
The Asterisk REST Interface (ARI) was created to address the limitations inherent in developing external or enhanced functionality outside Asterisk. While AGI allows you to trigger external applications, and AMI allows you to externally supervise and control calls in progress, any attempt to integrate both into a complete external application quickly becomes complex and kludgy. ARI allows developers to build a stand-alone and complete application, using Asterisk as the underlying engine.
As of this writing, ARI requires a very basic dialplan in order to
trigger the Stasis()
dialplan application, which then
hands the channel over to ARI. By the time you read this, it’s very likely
that this requirement has changed, as the Asterisk developer community has
actively been working on allowing ARI to spawn without any dialplan in the
middle.
Using an external interface such as ARI to control Asterisk is not necessarily going to make your life easier. The skills required to implement and troubleshoot applications of this type require a comprehensive skill set, in not only your language of choice, but also in Linux system administration, Asterisk administration, network troubleshooting, and fundamental telephony concepts. For the skilled developer, ARI can give you the power you want in your applications, but for someone learning, we recommend you consider mastering the dialplan before you dive into external development environments. The dialplan is peculiar, but it is also completely integrated, high-performance, and relatively easy to learn.
Having said that, let’s get you up and running with ARI.
This section gives you a simple working example of ARI. Later in the chapter we’ll cover things in more detail.1
In this quick-start section we will be using a very simple HTTP access layer. You must be very careful about putting this sort of configuration into production. If, for example, you are going to run your application on a separate machine and connect it to Asterisk across a socket, you will want a more secure connection. What we’re doing in this section is akin to a sailing club using dinghies to teach; useful as an introduction, but foolish and dangerous to set out to sea in such a craft.
You should already have the Asterisk web server running, so you simply need to verify that your /etc/asterisk/http.conf file looks similar to the following:
[general] enabled = yes bindaddr = 127.0.0.1
Next, a simple /etc/asterisk/ari.conf file is needed:
[general] enabled = yes pretty = yes [asterisk] type = user read_only = no password = whateveryoudodontusethispassword
OK, let’s load the ari
module now:
$ sudo asterisk -rx 'module load res_ari.so' Loaded res_ari.so => (Asterisk RESTful Interface)
Then, into our /etc/asterisk/extensions.conf file we need an
extension to trigger the Stasis()
dialplan
app:2
exten => 242,1,Noop() same => n,Stasis(zarniwoop) same => n,Hangup()
Reload your dialplan with
$ sudo asterisk -rx 'dialplan reload' Dialplan reloaded.
At this point it might be worthwhile to simply reload Asterisk:
$ sudo service asterisk restart
There are just a few steps left, and you’re ready to test your ARI environment.
Since ARI depends on WebSockets, we’ll need a tool to allow us to
test from the command line. The Node.js package manager
(npm
) will allow us to find and install the
wscat
tool we’ll use for our tests.
$ sudo yum -y install npm $ sudo npm install -g wscat /usr/bin/wscat -> /usr/lib/node_modules/wscat/bin/wscat /usr/lib +-- [email protected] +-- [email protected] +-- [email protected] ¦ +-- [email protected] +-- [email protected] +-- [email protected]
Now let’s light it up and see what we get!
$ wscat -c "ws://localhost:8088/ari/events?api_key= asterisk:whateveryoudodontusethispassword&app=zarniwoop" connected (press CTRL+C to quit) >
So far, so good. Let’s place a call to our
Stasis()
app and see what happens.
Open up a new SSH window (leave the other one as is so you can see
what happens in the wscat
session). Connect to the
Asterisk CLI in that new shell session:
$ sudo asterisk -rvvvv
Using one of your lab telephones, place a call to 242.
On the Asterisk CLI, you should see this:
*CLI> == Setting global variable 'SIPDOMAIN' to '172.29.1.57' -- Executing [242@sets:1] NoOp("PJSIP/SOFTPHONE_A-00000001", "") in new stack -- Executing [242@sets:2] Stasis("PJSIP/SOFTPHONE_A-00000001", "zarniwoop") in new stack
And
on the wscat
session, you should see this:
> < { "type": "StasisStart", "timestamp": "2019-01-27T21:43:43.720-0500", "args": [], "channel": { "id": "1548643423.2", "name": "PJSIP/SOFTPHONE_A-00000002", "state": "Ring", "caller": { "name": "101", "number": "SOFTPHONE_A" }, "connected": { "name": "", "number": "" }, "accountcode": "", "dialplan": { "context": "sets", "exten": "242", "priority": 2 }, "creationtime": "2019-01-27T21:43:43.709-0500", "language": "en" }, "asterisk_id": "08:00:27:27:bf:0e", "application": "zarniwoop" } >
OK, now we’re going to open yet another shell session3 so we can interact with this connection we’ve created. From this new shell, issue the following command:
$ curl -v -u asterisk:whateveryoudodontusethispassword -X POST "http://localhost:8088/ari/channels/1548643423.2/play?media=sound:believe-its-free" sd
Note the "id"
from the JSON
returned on the wscat
session must be used following
the 'channels/'
portion of the
curl
command. In other words, you must match the
channel identifier in your command to the channel identifier associated
with your call. In this manner, you can of course wrangle many calls
simultaneously.
Asterisk’s ARI has been developed to be compatible with the OpenAPI Specification (aka Swagger), which means that many tools compatible with this spec will work with ARI. As an example, you can interact with your ARI installation using Swagger-UI, which will be useful both for debugging and as a documentation source.
First up, we’ll need to expose our Asterisk HTTP server to the local network (currently it’s only allowing connections from 127.0.0.1). In your /etc/asterisk/http.conf file you’ll bind the HTTP server to the local IP address of your Asterisk machine:
$ sudo vim /etc/asterisk/http.conf ; Enable the built-in HTTP server, and only listen for connections on localhost. [general] enabled = yes ;bindaddr = 127.0.0.1 ; comment this out bindaddr = 172.29.1.57 ; LAN IP OF YOUR ASTERISK SERVER
Next, we’ll need to add a line to your /etc/asterisk/ari.conf file:
$ sudo vim /etc/asterisk/ari.conf [general] enabled = yes pretty = yes allowed_origins=http://ari.asterisk.org ...
Save and reload the http
and
ari
modules in Asterisk:
$ sudo asterisk -rx 'module reload http' ; sudo asterisk -rx 'module reload ari'
Now, from your development desktop, open up your browser and navigate to http://ari.asterisk.org.
You’ll see a web page similar to Figure 19-1.
Replace localhost
with the LAN
IP address of your Asterisk server, and in the api_key field, put your
ARI
user
:
password
from /etc/asterisk/ari.conf (for
example, asterisk:whateveryoudodontusethispassword
). If
you’ve got all the configuration correct, you will be rewarded with the
results in Figure 19-2.
You are looking at comprehensive documentation for your ARI module, and you can actually pass queries to it as well. This is a massively useful debugging aid, and kudos to the Digium folks for it.
As an example of what this is good for, select the endpoints:Endpoint resources
item, press the
GET
button beside /endpoints
, and you will see the screen shown
in Figure 19-3.
Well, go ahead—press the “Try it out!” button.
Note the "id"
of the channel in
the wscat
session, which you’ll want to copy for use
in the Swagger UI (you’ll see several lines of JSON output relating to
the call).
Perform the following actions on the channel using the Swagger UI
interface: POST: Answer
(answer the channel),
POST: hold
(place the call on hold), DELETE:
hold
(take the call off hold). Note what happens to the
channel in each case.
Use of this Swagger UI is also documented over at the Asterisk wiki.
This will greatly simplify your development and testing process.
OK, that’s the quick start. Let’s dive in deeper to ARI.
There are three components that work together to deliver ARI:
The RESTful interface, through which the external application communicates with Asterisk.
A WebSocket that passes information back to the external application from Asterisk (in JSON format).
The Stasis()
dialplan application, which
connects control of a channel to the external application.
The term RESTful stems from Representational State Transfer (REST), which is an architectural model for web services (as opposed to, say, a protocol). The term RESTful has commonly come to refer to any API that provides interaction through URLs, with data represented in JSON format.4 So, anything that is “RESTful” is supposed to adhere to the constraints of REST, but in practice may be implemented as a looser interpretation (which, if it gets the job done, may indeed be good enough).
The WebSocket connection is the mechanism that performs the communication between the internals of Asterisk and the RESTful interface. In Asterisk, events may happen that the client did not initiate, and the WebSocket allows Asterisk to signal those changes to the client.
Asterisk’s built-in HTTP server potentially provides other services across a web interface. For example, WebRTC also connects through the web server. If you are making changes or adding new services, make sure you not only test the item you’re working on, but also other services running through the same server, to ensure you haven’t inadvertently misconfigured something else.
The Stasis Message Bus allows the core of Asterisk to communicate events with
other modules and components. It is mostly internal to Asterisk;
however, in the case of ARI, a dialplan application named Stasis()
allows the dialplan to pass call
control to your external ARI application.
The Stasis()
application itself is required in order to signal to the dialplan
that call control is to be passed to the external program via
ARI.
Understanding the workings of Stasis()
is
generally not necessary unless you are going to be developing the
Asterisk product itself (i.e., joining the Asterisk development team and
coding new capabilities into Asterisk).
Typically, after your initial experimentation with ARI, you will want to implement a framework to help ease the work of developing your external application.
A production-grade application using ARI will benefit from the implementation of a framework to simplify development effort, add a layer of security, and provide a control environment.
There are several such libraries available. Which one you choose will in part be dictated by which language you prefer to use, and should also take into account whether the framework you’re interested in has an active community and is still being actively maintained.
The ones described next are listed in the Asterisk wiki. We examined the code repository for each, and while some projects are still actively maintained, others have not been updated in quite some time. If you are planning to implement one of these frameworks, you will need to do your own due diligence to ensure you can get support for it. In many cases, it may be worthwhile to reach out to the developers, and determine their consulting rates so you can ensure priority access to their time should you need it.
The ari-py framework was written by Digium in 2013–2014, and as of this writing had not been updated since then. This framework builds on Asterisk’s Swagger.py client.
Shortly after the relase of ari-py, it was forked into the aioari project, which delivers an asynchronous version of ari-py. This code has been more steadily updated since then (although as of this writing had not been updated since early 2018). This framework should be included in your evaluation of a Python framework for ARI.
If you are looking to develop ARI applications in Python, one of these two frameworks may be what you are looking for. If you are looking to build a large ARI application, you will need to ensure that you have carefully tested the performance implications of using Python for what you are doing.
Digium has provided samples for this framework (and others) at https://github.com/asterisk/ari-examples.
For the JavaScript folks, there is a Node.js-based ARI framework that was first released in early 2014, and as of this writing is still being updated. It is based on the automatically generated API that comes from swagger-js.
For JavaScript/Node developers, this is where you’ll want to start: https://github.com/asterisk/node-ari-client.
Digium has provided samples for this framework (and others) at https://github.com/asterisk/ari-examples.
The Windows folks are not left out. The AsterNET.ARI project delivers a framework for .NET that augments the AsterNET project (which also includes integration with Asterisk’s FastAGI and AMI interfaces).
You can find the repository for AsterNET.ARI here: https://github.com/skrusty/AsterNET.ARI.
Digium has provided samples for this framework (and others) at https://github.com/asterisk/ari-examples.
The ari4java project is one of the most actively developed ARI frameworks we have found. It has been developed since 2013, and the repository was receiving commits at the same time as this writing.
If Java is your language, you will want to check out the ari4java repository at https://github.com/l3nz/ari4java.
The phpari project delivers an ARI framework for the PHP community. It has been developed since 2014, and the repository was still being updated as of this writing.
For the PHP fans, you’ll find the repository at https://github.com/greenfieldtech-nirs/phpari.
If you’re used to writing in C++, there’s even an ARI project for you. The aricpp framework consists of header files only, so you can build its functions right into whatever you’re developing. This library has also been performance tested with SIPp, and while we don’t have any numbers on that, it seems to us that a compiled framework that has been performance tested is very much worth taking for a spin if you have the right skills.
One of the newer of the ARI frameworks, this project benefits from regular updates. Check it out at https://github.com/daniele77/aricpp.
Yes, Ruby also has an ARI framework.
You can find it at https://github.com/svoboda-jan/asterisk-ari.
ARI provides a current-generation RESTful API that can be used to develop communications applications using popular development languages. Through it, an experienced developer can harness the power of the most successful PBX platform in history. This allows next-generation communications applications to interact with legacy telecommunications protocols and applications, which could prove very useful as we are increasingly called to bridge the gap between past, present, and future communications technologies.
1 Although, to be honest, there’s really nothing more to the configuration unless you’re implementing one of the frameworks, which is strongly recommended if you’re going to put this into a production environment, and which we will explore later.
2 We named the app “zarniwoop” because “hello-world” was used in the Digium wiki on ARI, and it seemed best to avoid overlap. You can of course name it anything you wish.
3 If your computer has only one screen, now is probably the point where you’re thinking what a good idea it would be to have more of them.
4 Strictly speaking, REST is far more than that, but as a practical matter, these days it seems not uncommon to assume that a REST API will be URL and JSON-based, simply because so many such services are presented in those formats.