Applying Adhearsion to Asterisk

Tackle your sticky VoIP projects with Ruby and Adhearsion.

Following the trend of other corporate servers shifting from closed-source platforms like Windows NT and UNIX, VoIP too now booms with an exodus to the open-source Asterisk PBX and Linux. In its own picture, Asterisk looks readier than ever to meet these needs. The great folks at Digium, Asterisk's maintaining company, stress product quality and lead VoIP innovation.

Integrating technologies with VoIP also makes the picture even prettier. With standard computers crunching the calls, connecting the dots plainly makes sense. Traditional ways to integrate Asterisk really exist as hacks though, not as comprehensive solutions.

Enter Adhearsion

This new open-source framework takes on integration issues ranging from enterprise must-haves to living-room hacking projects. Written in Ruby, Adhearsion comes out of the box with more than what many companies spend thousands on. Though its name derives from being “adhesion you can hear”, it can work even without Asterisk when trying to splice two or more technologies together outside of the VoIP picture frame. Because Ruby and Adhearsion both aim to improve productivity, VoIP systems now more than ever make fun projects for your free time or effective tools in bringing your employees, customers and the world closer.

When a call comes in on an Asterisk server managed by Adhearsion, Asterisk acts as a metaphorical kernel for the call by managing low-level hardware, converting codecs, canceling echo and so forth. For the logic it should perform during the call, such as playing messages, connecting through to someone or taking input, it establishes a TCP connection to a running Adhearsion dæmon and receives commands one at a time, executing each and sending back a response.

Let's get a working Adhearsion box running to demonstrate.

Up and Running

Adhearsion, like most other Ruby projects, uses the fantastic package manager RubyGems. If you read Linux Journal's July '06 issue on Ruby or have picked at the language, you've likely bumped into this great software. If not, package managers for any popular Linux distro barely differ. The Adhearsion installation process constitutes installing Ruby and RubyGems, then pulling Adhearsion down with a gem install command.

The installation example below uses Ubuntu/Debian's apt-get package manager. You, therefore, may need to make minor modifications to the package names for your distro. If you don't have a RubyGems system package, drop by its Web site (see Resources) and pick up the tarball:

apt-get install ruby1.8 ruby1.8-dev irb1.8
tar zxf rubygems*.tgz
cd rubygems*
ruby setup.rb
gem install adhearsion --include-dependencies

With the last command, RubyGems created the ahn (pronounced Anne) command.

You can use ahn to create new Adhearsion projects, execute an Adhearsion process normally or as a dæmon, install open-source framework extensions remotely, read help documentation and so forth. Type ahn help for more information.

This guide assumes you have an existing Asterisk server configured. If you would like more information on how to do this, see the Resources section. It takes adding only a simple instruction to the extensions.conf configuration script to have Asterisk utilize Adhearsion. If you had your phone users routed to your “internal” context, you would modify the “internal” context's definition as such:

exten => _X.,1,AGI(agi://

Next, create a new Adhearsion project with the command:

ahn create ~/helloworld

This generates an entire directory structure with which you can mingle safely. To start up Adhearsion, supply the path to your Adhearsion directory to ahn:

ahn start ~/helloworld

Read on to learn ways you can modify this new project to suit your interests.

Make Call Instructions Fun

Traditionally, engineers route Asterisk calls in one of two ways: modifying the extensions.conf file or writing an Asterisk Gateway Interface (think CGI) script. Most generally use the former but, in situations where integration matters, one may use them together. Typically, developers write AGI scripts on the filesystem of their Asterisk machine, which communicate plain text over STDIN and STDOUT.

But, trouble arises when this scales both in complexity of code and complexity of use. Because Asterisk executes this script as a subprocess, it actually builds up whatever overhead is needed for the AGI program (for example, the Perl interpreter or a database socket), executes the code and then tears it all down again. Although tolerable in smaller situations, processes carry greater tolls on memory and running time as concurrent use increases. Additionally, without a framework, scripts in this way also contain suboptimal amounts of repetition.

Adhearsion utilizes Asterisk's FastAGI feature for managing calls from another IP-addressable machine. In this way, precious RAM and CPU cycles receive virtually no impact on the Asterisk box and, just as important, Adhearsion has already established the overhead for each call before it comes in.

With your new example Adhearsion project created earlier, open your extensions.rb file. Below, I've included an example file from which you can get a feel for how Adhearsion works to handle calls. Take a minute now to read it over:

# File extensions.rb
internal {
  case extension
    when 101...200
      employee = User.find_by_extension extension
      if employee.busy? then voicemail extension
        dial employee, :for => 10.rings
        voicemail unless last_call_successful?
    when 888
      play weather_report("Dallas Texas")
    when 999 then +joker_voicemail

joker_voicemail {
  play %w"a-connect-charge-of 22
            cents-per-minute will-apply"
  sleep 2.seconds
  play 'just-kidding-not-upset'

If you feel adventurous, try using this now with any phones on your Asterisk box.

Note that this is all valid Ruby. Ruby fundamentally permits the modification of how aspects of the language function. As such, Ruby code can become modified for a particular need or particular domain of needs—hence the name commonly used in the Ruby scene: domain-specific language or DSL. The full benefit of the Ruby language remains, however, giving it the best of both worlds.

Because our example Asterisk extensions.conf from above invokes Adhearsion within a context named internal, Adhearsion maps this directly over by convention. Adhearsion creates many call-related variables as simple local variables before it processes a context. The case statement for the auto-generated extension variable used shows Ruby's great support for ranges of numbers, but a Perl-like regular expression literal could very well replace this.

The next line employee = User.find_by_extension extension may prove surprisingly subtle. You easily can infer there exists some collection of users with extensions and some method of finding them by their extension. If ActiveRecord is new to you, you probably didn't realize immediately that this actually abstracts database access. Before diving into a more complete explanation of how this works, let's finish grokking this file.

Implementations for determining whether the user should be disturbed can vary, but we need to know only a yes or no answer. Users are allowed to remain focused by having callers sent silently to their voice mail.



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Worth mentioning that 999 is

Ross's picture

Worth mentioning that 999 is a bad example to use for things like this as it's the emergency services number in the UK and a couple of other countries... Most Voip ATAs that have a PSTN fallback in these countries will route 999 over the PSTN and it will never reach Asterisk (not to mention you'll have a somewhat annoyed Emergency Operator on the line!)

Simply Amazing

Anonymous's picture

Even though this piece of software is beta, I have been amazed how easy it is do things that would be otherwise difficult to implement. Rails catapulted Ruby in the web dev arena, and I think adhearsion is about to do the same in the asterisk arena.
Go !