Applying Adhearsion to Asterisk

Tackle your sticky VoIP projects with Ruby and Adhearsion.

Users dialing 888 have a weather report converted from an Internet source to a series of played sound files that come with the standard asterisk-sounds package. If they dial 999, things get fancy—the plus sign before joker_voicemail does just what you might think: it executes the joker_voicemail block.

This joker_voicemail section uses %w"", a fantastic Ruby literal for an array of words. Automatically, Ruby will break apart this string by whitespace, creating an array containing a series of sounds intuitively named for the speech they produce. But you ask, “What about this 22 here?”

When Adhearsion encounters numbers, instead of executing the Playback() application, it uses SayNumbers(). This breaks the number into the words twenty and two—two words for which sounds do exist. The end result contains no commas, no quotes between indices and no specification of the application used to play the file. Why should it?

You can find more detailed, working dial plans and documentation freely on the Adhearsion Web site. See the Resources section for more information.

Powerfully Use Your Database Software

If you've checked out Ruby on Rails, you likely know of its rock-star object relational mapper ActiveRecord. Instead of keeping ActiveRecord deeply intertwined with the Rails framework, the brilliant folks over at 37signals allow anyone to utilize this fantastic library through a gem. When you install Adhearsion, the --include-dependencies part pulls this in for you.

From a database modeling perspective, typical VoIP applications have users and groups of users. Therefore, in our database—whether you use MySQL, PostgreSQL, SQLite or nearly any other popular relational database management system—it makes sense to have a table called users and a table called groups. Because each record represents an individual user or group in the database, it also makes sense to have a User object and a Group object. Beginning to see how an object relational mapper applies here?

Here's a tangible, tasty example:

class User < ActiveRecord::Base
    belongs_to :group
    validates_uniqueness_of :extension
    def busy?
      # Implemented how you wish

class Group < ActiveRecord::Base
   has_many :users

This is where the magic happens. With so little code, ActiveRecord can actually make a lot of very logical conclusions. Given the class names User and Group, it finds their appropriate table by lowercasing them and then finding the plural forms users and groups, respectively. If we had used the class name Person instead of User, ActiveRecord would have assumed its associated table to be people.

To help ourselves out, we've told ActiveRecord that a User belongs to a Group and that Groups have many users. Given this, the foreign key to which a record in users maps is assumed to be group_id by default. With this identified, one can retrieve the Group object to which a User instance belongs simply by calling If the jay variable belonged to the Group codemecca, jay and any other potential variables could be retrieved by codemecca.users.

So let's take a look at the dial plan example above. We're calling a method on User by the name of find_by_extension. Did we have to create that method anywhere here? No. But why not? ActiveRecord actually created the method, because it peeked inside the users table, found the names of its columns and created methods like find_by_extension. Explicated into a MySQL select statement, it would read SELECT * FROM users WHERE EXTENSION='somenumber' LIMIT 1;. Nice shortcut, eh?

Use VoIP and the Web Together to Collaborate

In a corporate environment, businesses depend on collaboration, and people look for any way to improve it with good reason. Adhearsion offers a free collaboration tool that, in the spirit of adhering everything together, takes traditional collaboration a step further.

Modern IP desk phones generally have a microbrowser that can pull down XML documents over HTTP and translate them to an interactive menu on the device. Although this may seem like a great technology, there's a significant caveat: every vendor's XML format differs, none document the feature very well and the available features vary vastly. Some vendors support images, HTML forms and a special URI for initializing a call, whereas others give you about three or four XML elements from which you can choose.

If vendors can't collaborate on consistency, something must abstract their differences (and quirks) by translating. Micromenus do exactly that with a few hints of additional cleverness.

Since the Micromenus sub-framework exists as a built-in helper, you manage the menus in the config/helpers/micromenus/ directory. When an HTTP request comes in over port 1337, Adhearsion takes the first argument in the URL's path as the desired filename. For example, if you programmed a phone to use as its Micromenus URL, Adhearsion would attempt loading the file config/helpers/micromenus/main.rb. Modifying and creating files here takes effect even without restarting Adhearsion.

Using this example filename, let's fill it with some Micromenu code:

# config/helpers/micromenus/main.rb
call "Check your voicemail" do

call 505, "Call Support"

item "Join a conference" do

    call 'Join Marketing' do
        join :marketing

    call 'Join Support' do
        join :support

    call 'Join Ninjas' do
        join :ninjas

item "Weather forecasts" do
    call "New York, New York" do
        play weather_report('New York, New York')

    call "San Jose, California" do
    play weather_report('San Jose, California')

    call "University of Texas at Dallas" do
      play weather_report(75080)

item "System Administration" do
    item 'Uptime: ' + %x'uptime'
    item "View Current SIP users" do
        PBX.sip_users.each do |user|
            item "#{user[:username]@#{user[:ip]}"

This simple example, albeit very terse, produces an entire, respectable company intranet. Giving the item method a block automatically turns it into a link, abstracting the URL. Placing actual Ruby code in a submenu gives the menu behavior. Using the call method on a phone actually places the call to either the extension specified (without a block) or, because Adhearsion handles the call itself too, executes the dial plan behavior within the block when it finds the user generated a call through a Micromenu. This exemplifies the benefits of having both call routing and Web-based collaboration adhered this closely together in the same framework.



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 !