Chapter 10. Asterisk Manager Interface (AMI) and Adhearsion

Do but take care to express yourself in a plain, easy Manner, in well-chosen, significant and decent Terms, and to give a harmonious and pleasing Turn to your Periods: study to explain your Thoughts, and set them in the truest Light, labouring as much as possible, not to leave them dark nor intricate, but clear and intelligible.

Miguel de Cervantes, Preface to Don Quixote

The Manager Interface

The Asterisk Manager Interface (AMI) is a powerful programmatic interface. It allows external programs to both control and monitor an Asterisk system.[125] This interface is often used to integrate Asterisk with existing business processes and systems, CRM (Customer Relationship Management) software. It can also be used for a wide variety of applications, such as automated dialers and click-to-call systems.

The Asterisk Manager Interface listens for connections on a network port. A client program can then connect to the Asterisk Manager Interface on that port, authenticate itself, and send commands to Asterisk. Asterisk will then respond to the request, as well as update the client program with the status of the system.

To use the Manager, you must define an account in the file /etc/asterisk/manager.conf. This file will look something like this:

[general]
enabled = yes
port = 5038
bindaddr = 0.0.0.0

[oreilly]
secret = notvery
;deny=0.0.0.0/0.0.0.0
;permit=209.16.236.73/255.255.255.0
read = system,call,log,verbose,command,agent,user
write = system,call,log,verbose,command,agent,user

In the [general] section, you have to enable the service by setting the parameter enabled = yes. You will need to reload the Manager in order to have this change take effect (module reload manager from the Asterisk console). The TCP port defaults to 5038.

Next, you create a section for each user that will authenticate to the system. For each user, you will specify the username in square brackets ([ ]), followed by the password for that user (secret), any IP addresses you wish to deny access to, any IP addresses you wish to permit access to, and the read and write permissions for that user.

Warning

It is very important to understand that other than a clear text password and the ability to restrict IP addresses, there is no security of any kind on the Manager interface. If you are running Manager on an untrusted network (or have any other complex needs), you should consider using David Troy’s excellent AstManProxy to handle all of your connections to the manager API.

Connecting to the Manager Interface

It is important to keep in mind that the Manager interface is designed to be used by programs, not fingers. That’s not to say that you can’t issue commands to it directly—just don’t expect a typical console interface, because that’s not what Manager is for.

Commands to Manager are delivered in packages with the following syntax (lines are terminated with CR+LF):[126]

Action: <action type>
Key 1: Value 1
Key 2: Value 2
etc ...
Variable: Value
Variable: Value
etc...

For example, to authenticate with Manager (which is required if you expect to have any interaction whatsoever), you would send the following:

Action: login
Username: oreilly
Secret: notvery
<CR+LF>

An extra CR+LF on a blank line will submit the entire package to Manager.

Once authenticated, you will be able to initiate actions, as well as see events generated by Asterisk. On a busy system, this can get quite complicated and become totally impossible to keep track of with the unaided eye. To turn keep Asterisk from sending events, you can add the Events parameter to your login command, like this:

Action: login
Username: oreilly
Secret: notvery
Events: off
<CR+LF>

If you’re worried about sending your secret across the wire in plain text (which you should be), you can also authenticate using an MD5 challenge-response system, which works very similar to HTTP digest authentication. To do this, you first call the Challenge action, which will present you with a challenge token:

          Action: Challenge
AuthType: MD5

          
Response: SuccessChallenge: 840415273

You can then take that challenge token, concatenate the plaintext secret onto the end of it, and calculate the MD5 checksum of the resulting string. The result can then be used to login without passing your secret in plain text.

          Action: Login
AuthType: MD5
Username: Admin
Key: e7a056e1488882c6c509bbe71a049978

          
Response: Success
Message: Authentication accepted

Sending Commands

Once you’ve successfully logged into the AMI system, you can send commands to Asterisk by using the other actions. We’ll show a few commands here so that you can get a feel for how they work.

Transferring a call

The Redirect action can be used to transfer a call. After logging in, you should send an action like the one below:

Action: Redirect
Channel: SIP/John-ae201e78
Context: Lab
Exten: 6001
Priority: 1
ActionID: 2340981650981

Note

For each action you sent over the manager interface, you can send along an arbitrary ActionID value. This will allow you to recognize the responses from Asterisk as being related to your actions. It is strongly recommended that you send a unique ActionID with each of your AMI commands.

This URL transfers the specified channel to another extension and priority in the dialplan. The response to this action is:

Response: Success
ActionID: 2340981650981
Message: Redirect Successful

Reading a configuration file

To read an Asterisk configuration file via the Manger interface, we can use the the GetConfig action. The GetConfig action returns the contents of a configuration file, or portion thereof. The following command retrieves the contents of the file users.conf.

Action: GetConfig
Filename: users.conf
ActionID: 9873497149817

Asterisk then returns the contents of the users.conf file. The response looks like:

Response: Success
ActionID: 987397149817
Category-000000: general
Line-000000-000000: fullname=New User
Line-000000-000001: userbase=6000
Line-000000-000002: hasvoicemail=yes
Line-000000-000003: hassip=yes
Line-000000-000004: hasiax=yes
Line-000000-000005: hasmanager=no
Line-000000-000006: callwaiting=yes
Line-000000-000007: threewaycalling=yes
Line-000000-000008: callwaitingcallerid=yes
Line-000000-000009: transfer=yes
Line-000000-000010: canpark=yes
Line-000000-000011: cancallforward=yes
Line-000000-000012: callreturn=yes
Line-000000-000013: callgroup=1
Line-000000-000014: pickupgroup=1
Line-000000-000015: host=dynamic

Updating configuration files

It is often useful to be able to update an Asterisk configuration file via the Asterisk Manager interface. The UpdateConfig action is used to update one or more settings in a configuration file. For example, to delete a user named 6003 from users.conf you could issue the following command:

Action: UpdateConfig
Filename: users.conf
Reload: yes
SrcFilename: users.conf
DstFilename: users.conf
Action-00000: delcat
Cat-00000: 6003
ActionID: 5298795987243

Obviously, we’ve only scratched the surface of the many different actions available as part of the Asterisk Manager Interface. For a more detailed listing of the available commands, see Appendix F.

The Flash Operator Panel

The Flash Operator Panel (FOP) is one of the most popular examples of the power of the Manager interface. FOP presents a web-based visual view of your system and allows you control of calls.

FOP is most commonly used to enable a live attendant to view the users in the system and connect calls between them. It can also be used in a call-center environment to provide CRM-triggered screen pops.[127]

The FOP management interface is shown in Figure 10-1. To grab a copy of FOP, head to http://www.asternic.org.

The Flash Operator Panel management interface
Figure 10-1. The Flash Operator Panel management interface

FOP isn’t all that difficult to set up, but it does require several steps to configure. The configuration of FOP is beyond the scope of this book, but if you head on over to the FOP web site you will find the latest documentation detailing the installation and configuration process.

FOP has a fantastic community and a popular mailing list. The success of FOP has also been aided by its inclusion in Trixbox.

Asterisk Development with Adhearsion

Recently, a new bit of technology has come along which has the potential to change the way we create dialplans.[128]

A New Approach to Dialplans

Asterisk has matured both in technological innovation and in popularity, but as one becomes more and more immersed in this wonderful world, one cannot help but bump into limitations. When you handle a lot of complex, enterprise-grade scripting with Asterisk alone, you will face many obstacles using dialplan logic. As flexible and powerful as the dialplan is, as a programming language it is quite odd, and much less flexible than most modern scripting languages. When one needs to provide advanced logic, the dialplan, the GUI, and even the more advanced AEL can become very frustrating.

As you build more and more complexity into your dialplans, some of the following may cause you some head-scratching:

  • Conditional looping and branching

  • Variables

  • Complex data structures

  • Database/LDAP integration

  • Use of third-party libraries

  • Exchanging and distributing VoIP functionality

  • Extending the configuration languages

  • Poor error handling

  • Poor date and time handling

  • Pattern matching

  • Usage consistency

  • Source code organization

Many people addressed these matters by writing the advanced logic in external programs such as Perl and PHP, and connecting to Asterisk via AMI and AGI. Unfortunately, while the desired power was now available, these interactions did not always simplify things for the developer. To the contrary, they often made development more complex. Using existing technologies in Asterisk, but aiming to deliver power and simplicity, Adhearsion has a new approach.

Asterisk Development with Adhearsion

Adhearsion is an open source (LGPL) framework that is designed to improve Asterisk solution development. It rests above an Asterisk system, handling parts or all of the dialplan and, in a few unique ways, manages access to Asterisk with several improved interfaces. Because it runs as a separate daemon process and integrates through the already-present Gateway (AGI) and Manager (AMI) interfaces, configuring a context to use Adhearsion is as simple as adding a few lines to your dialplan or adding a user to manager.conf.

Adhearsion primarily uses the highly dynamic, object-oriented Ruby programming language, but has optional support for other languages such as C or Java. In the VoIP world, many things exist as conceptual objects, which means that object-oriented programming can make a lot of sense. Those familiar with Python, Perl, or other scripting languages should have no trouble picking up Ruby, and for those who don’t, Ruby is an excellent choice for your first scripting language.

Installing Adhearsion

Ruby software is generally installed through Ruby’s package manager (similar to Linux package managers, but for the Ruby platform exclusively). Adhearsion exists as a gem in the standard RubyGems trove so, with Ruby and RubyGems installed, Adhearsion is only one install command away.

Installing Ruby/RubyGems on AsteriskNOW

AsteriskNOW comes standard with Ruby but not RubyGems (for support reasons). Thankfully, RubyGems can be easily installed from the Ruby rPath trove with the following command:

conary update rubygems=ruby.rpath.org@rpl:devel
source /etc/profile

Installing Ruby/RubyGems on Linux

Most Linux distributions’ package managers host a Ruby package, though some do not yet have RubyGems. With your respective distro’s preferred software management application, install Ruby 1.8.5 or later and RubyGems if available. If RubyGems is not available in CentOS, you can install Ruby by typing:

yum install ruby

Next, we need RubyGems. You can get that by navigating to /usr/src/, and entering:

wget http://rubyforge.org/frs/download.php/20585/rubygems-0.9.3.tgz
tar zxvf rubygems-0.9.3.tgz
cd rubygems-0.9.3
ruby setup.rb

Installing Ruby/RubyGems on Mac OS X

Ruby actually ships standard with OS X, but you will need to upgrade it and install RubyGems from MacPorts, an OS X package manager. With MacPorts installed, (available from http://www.macports.org if you do not already have it) you can install Ruby and RubyGems with the following command:

sudo port install ruby rb-rubygems

You may also need to add /opt/local/bin to your PATH variable in /etc/profile.

Ruby/RubyGems on Windows

A fantastic “one-click installer” exists for Windows. This installer will automatically install Ruby, RubyGems, and a few commonly used gems all in a matter of minutes. You can download the installer from http://rubyforge.org/projects/rubyinstaller.

Installing Adhearsion from RubyGems

Once you’ve followed one of the previous set of instructions for your system to fetch Ruby and RubyGems, install Adhearsion with the following command:

gem install adhearsion

If any dependencies are found, you will probably need to allow them to install for Adhearsion to work correctly.

Exploring a New Adhearsion Project

With Adhearsion installed, you can begin creating and initializing a new Adhearsion project with the newly created ahn command, a command-line utility that manages nearly everything in Adhearsion.

A sample command for creating a new Adhearsion project is as follows:

ahn create ~/newproject

This creates a folder at the destination specified containing the directory and file hierarchy Adhearsion needs to operate. Right away, you should be able to execute the newly created application by running:

ahn start ~/newproject

To familiarize yourself with the Adhearsion system, take a look through the application’s folders and read the accompanying documentation.

Adhearsion dialplan writing

The ability to write dialplans in Adhearsion is typically the first feature newcomers use. Since Ruby permits such fine-grained modification of the language itself at runtime, one of the things Adhearsion does is make aesthetic changes, which are intended to streamline the process of developing dialplans.

Below is an Adhearsion Hello World application:

my_first_context {
  play "hello-world"
}

Though this is completely valid Ruby syntax, not all Ruby applications look like this. Adhearsion makes the declaration of context names comfortable by interpreting the dialplan script specially. Your scripts will be located in the root folder of your newly created Adhearsion application.

As calls come into Asterisk and subsequently Adhearsion, Adhearsion invokes its own version of the context name from which the AGI request originated. Given this, we should ensure that a context in extensions.conf has this same name and forwards calls properly to Adhearsion.

The syntax for directing calls to Adhearsion is as follows:

[my_first_context]
exten => _.,1,AGI(agi://127.0.0.1)

This catches any pattern dialed and goes off to Adhearsion via AGI to handle the call-processing instructions for us. The IP provided here should of course be replaced with the necessary IP to reach your Adhearsion machine.

Now that you have a basic understanding of how Adhearsion and Asterisk interact, here is a more real-world dialplan example in Adhearsion:

internal {
  case extension
when 10..99
  dial SIP/extension
when 6000..6020, 7000..7030
  # Join a MeetMe conference with "join"
  join extension
when _'21XX'
  if Time.now.hour.between? 2, 10
    dial SIP/"berlin-office"/extension[2..4]
  else speak "The German office is closed"
  end
when US_NUMBER
  dial SIP/'us-trunk-out'/extension
when /^\d{11,}$/ # Perl-like regular expression
  # Pass any other long numbers straight to our trunk.
  dial IAX/'intl-trunk-out'/extension
else
  play %w'sorry invalid extension please-try-again'
  end
}

With just this small amount of code we accomplish quite a lot. Even with limited or no knowledge of Ruby, you can probably infer the following things:

  • We use a switch-like statement on the “extension” variable (which Adhearsion creates for us) and branch depending on that.

  • Dialing a number between 10 and 99 routes us to the SIP peer with the dialed numerical username.

  • Any number dialed between 6000 and 6200 or between 7000 and 7030 goes to a MeetMe conference of that same number. This of course requires meetme.conf to have these conference numbers configured.

  • The _’21XX’ option comes straight from Asterisk’s pattern style. Prepending a String with an underscore in Adhearsion secretly invokes a method that returns a Ruby regular expression. In a Ruby “case” statement, regular expressions can be used in a “when” statement to check against a pattern. The end effect should be very familiar to those with extensions.conf writing experience.

  • Adhearsion’s syntax for representing channels also comes straight from Asterisk’s traditional format. SIP/123 can be used verbatim to represent the SIP peer 123. If a trunk were involved, SIP/trunkname/username would act as you would expect.

  • The speak() method abstracts an underlying text-to-speech engine. This can be configured to use most of the popular engines.

  • A full-blown Perl-like regular can be used in a when statement to perform more sophisticated pattern matching if Asterisk’s patterns do not suffice.

  • Adhearsion defines a few constants that may be useful to someone writing dialplans. The US_NUMBER constant here is a regular expression for matching an American number.

  • If you find the need to play several files in sequence, play() accepts an Array of filenames. By luck, Ruby has a convenient way of creating an Array of Strings.

This is of course just a simple example and covers only the absolute basics of Adhearsion’s dialplan authoring capabilities.

Database integration

Though immensely successful in the web development space for serving dynamic content, database integration has always been an underutilized possibility for driving dynamic voice applications with Asterisk. Most Asterisk applications that do accomplish database integration outsource the complexity to a PHP or Perl AGI script because the extensions.conf or AEL grammars are simply impractical for the level of sophistication required.

Adhearsion uses a database integration library, called ActiveRecord, developed by the makers of the Ruby on Rails framework. With ActiveRecord, the end user seldom, if ever, writes SQL statements. Instead, the developer accesses the database just like any Ruby object. Because Ruby allows such flexible dynamism, access to the database looks and feels quite natural. Additionally, ActiveRecord abstracts the differences between database management systems, making your database access implementation agnostic.

Without going too much into the internals of ActiveRecord and more sophisticated uses of it, let us consider the following simple MySQL schema:

CREATE TABLE groups (
 `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
 `description` varchar(255) DEFAULT NULL,
 `hourly_rate` decimal DEFAULT NULL
);

CREATE TABLE customers (
 `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
 `name` varchar(255) DEFAULT NULL,
 `phone_number` varchar(10) DEFAULT NULL,
 `usage_this_month` int(11) DEFAULT 0,
 `group_id` int(11) DEFAULT NULL
);

In practice we would obviously store much more information about the customer and keep the service usage information in a database-driven call detail record, but this degree of simplicity helps demonstrate ActiveRecord fundamentals more effectively.

To connect Adhearsion to this database, one simply specifies the database access information in a YAML configuration file like so:

adapter: mysql
host: localhost
database: adhearsion
username: root
password: pass

This tells Adhearsion how to connect to the database, but how we access information in the tables depends on how we model our ActiveRecord objects. Since an object is an instance of a class, we write a class definition to wrap around each table. We define simple properties and relationships in the class with the superclass’s methods.

Here are two classes we may use with the aforementioned tables:

class Customer < ActiveRecord::Base
  belongs_to :group

  validates_presence_of   :name, :phone_number
  validates_uniqueness_of :phone_number
  validates_associated    :group

  def total_bill
self.group.hourly_rate * self.usage_this_month / 1.hour
  end
end

class Group < ActiveRecord::Base
  has_many :customers
  validates_presence_of :description, :hourly_rate  
end

From just this small amount of information, ActiveRecord can make a lot of logical inferences. When these classes interpret, ActiveRecord assumes the table names to be customers and groups respectively by lowercasing the classes’ names and making them plural. If this convention is not desired, the author can easily override it. Additionally, at interpretation time, ActiveRecord actually peeks into the database’s columns and makes available many new dynamically created methods.

The belongs_to and has_many methods in this example define relationships between Customers and Groups. Notice again how ActiveRecord uses pluralization to make the code more expressive in the has_many :customers line. From this example, we also see several validations—policies that ActiveRecord will enforce. When creating a new Customer we must provide a name and phone_number at the bare minimum. No two phone numbers can conflict. Every Customer must have a Group. Every Group must have a description and hourly_rate. These help both the developer and the database stay on track.

Also, notice the total_bill method in the Customer class. On any Customer object we extract from the database, we can call this method, which multiplies the hourly_rate value of the group to which the Customer belongs by the Customer’s own phone usage this month (in seconds).

Here are a few examples that may clarify the usefulness of having Ruby objects abstract database logic:

everyone = Customer.find :all

jay = Customer.find_by_name "Jay Phillips"
jay.phone_number # Performs a SELECT statement
jay.total_bill   # Performs arithmetic on several SELECT statements
jay.group.customers.average :usage_this_month

jay.group.destroy
jay.group = Group.create :description => "New cool group!",
                         :hourly_rate => 1.23
jay.save

Because the database integration here becomes much more natural, Asterisk dialplans becomes much more expressive as well. Below is a sample dialplan of a service provider that imposes a time limit on outgoing calls using information from the database. To remain simple:

# Let's assume we're offering VoIP service to customers
# whom we can identify with their callerid.

service {
  # The line of code below performs an SQL SELECT
  # statement on our database. The find_by_phone_number()
  # method was created automatically because ActiveRecord
  # found a phone_number column in the database. Adhearsion
  # creates the "callerid" variable for us.
  caller = Customer.find_by_phone_number callerid

  usage = caller.usage_this_month
  if usage >= 100.hours
    play "sorry-cant-let-you-do-that"
  else
    play %w'to-hear-your-account-balance press-1 
            otherwise wait-moment'
    choice = wait_for_digit 3.seconds

    p choice
    if choice == 1
      charge = usage / 60.0 * caller.group.hourly_rate
      play %W"your-account will-reflect-charge-of $#{charge}
              this month for #{usage / 60} minutes and
              #{usage % 60} seconds"
    end

    # We can also write back to the "usage_this_month"
    # property of "caller". When the time method finishes,
    # the database will be updated for this caller.
    caller.usage_this_month += time do
      # Code in this block is timed.
      dial IAX/'main-trunk'/extension
    end
    caller.save
  end
}

Robust database integration like this through Adhearsion brings new ease to developing for and managing a PBX. Centrally persistent information allows Asterisk to integrate with other services cleanly while empowering more valuable services whose needs are beyond that of traditional Asterisk development technologies.

Distributing and reusing code

Because an Adhearsion application resides within a single folder, completely copying the VoIP application is as simple as zipping the files. For one of the first times in the Asterisk community, users can easily exchange and build upon one another’s successful application. In fact, open sourcing individual Adhearsion applications is greatly encouraged.

Additionally, on a more localized level, users can reuse Adhearsion framework extensions, called helpers, or roll their own. Helpers range from entire sub-frameworks like the Micromenus framework for integrating with on-phone micro-browsers to adding a trivial new dialplan method that returns a random quote by Oscar Wilde.

Below is a simple Adhearsion helper written in Ruby. It creates a new method that will exist across the entire framework, including the dialplan. For simplicity’s sake, the method downloads an XML document at a specified HTTP URL and converts it to a Ruby Hash object (Ruby’s associative array type):

def remote_parse url
  Hash.from_xml open(url).read
end

Note that these three lines can work as the entire contents of a helper file. When Adhearsion boots, it executes the script in a way that makes any methods or classes defined available anywhere in the system.

For some issues, particularly ones of scaling Adhearsion, it may be necessary to profile out bottlenecks to the king of efficiency: C. Below is a sample Adhearsion helper that returns the factorial of a number given:

int fast_factorial(int input) {
  int fact = 1, count = 1;
  while(count <= input) {
    fact *= count++;
  }
  return fact;
}

Again, the code here can exist as the entire contents of a helper file. In this case, because it is written in C, it should have the name factorial.alien.c. This tells Adhearsion to invoke its algorithm to read the file, add in the standard C and Ruby language development headers, compile it, cache the shared object, load it into the interpreter, and then wrap the C method in a Ruby equivalent. Below is a sample dialplan that simply speaks back the factorial of six using this C helper:

fast_test {
  num = fast_factorial 6
  play num
}

Note that the C method becomes a first-class Ruby method. Ruby number objects passed to the method are converted to C’s “int” primitive, and the return value is converted back to a Ruby number object.

Helpers promise robust albeit simple extensibility to a VoIP engineer’s toolbox, but, best of all, useful helpers can be traded and benefit the entire community.

Integrate with Your Desk Phone Using Micromenus

With increasing competition between modern IP-enabled desk phone manufacturers, the microbrowser feature has snuck in relatively unnoticed and underutilized. The principle is simple: physical desk phones construct interactive menus on a phone by pulling XML over HTTP or the like. Contending interests, however, lead this technology amiss: every vendor’s XML differs, microbrowsers are often quirky, and available features vary vastly.

The Micromenus framework exists as an Adhearsion helper and aims to abstract the differences between vendors’ phones. For this very particular development domain (i.e., creating menus), Micromenus use a very simple Ruby-based “Domain Specific Language” to program logic cleanly and independent of any phone brands.

Below is a simple example Micromenu:

image 'company-logo'
item "Call an Employee" do
  # Creates a list of employees as callable links from a database.
  Employee.find(:all).each do |someone|
    # Simply select someone to call that person on your phone.
    call someone.extension, someone.full_name
  end
end
item "Weather Information" do
  call "Hear the weather report" do
    play weather_report("Portland, OR")
  end
  item "Current: " + weather("Portland, OR")[:current][:temp]
end
item "System Uptime: " + `uptime`

A list item displays in two ways. If given only a text String, Micromenus renders only a text element. If the arguments contain a do/end block of nested information, that text becomes a link to a sub-page rendering that nested content.

A call item also has two uses, each producing a link which, when selected, initiates a call. When call receives no do/end block, it simulates physically dialing the number given as the first argument. When a do/end block exists and all calls route through Adhearsion, selecting that item executes the dialplan functionality within the block. This is a great example of how handling the dialplans and on-screen microbrowsers within the same framework pays off well.

From this example we can see a few other neat things about Micromenus:

  • Micromenus support sending images. If the requesting phone does not support images, the response will have no mention of them.

  • All Adhearsion helpers work here, too. We use the weather helper in this example.

  • The Micromenus sub-framework can use Adhearsion’s database integration.

  • Ruby can execute a command inside backticks and return the result as a String. We report the uptime here with it.

This example of course assumes that you have configured your application’s database integration properly and have an Employee class mapping to a table with an extension and full_name column.

Because Micromenus simply render varying responses over HTTP, a normal web browser can make a request to the Micromenus’ server, too. For these more high-tech endpoints, Micromenus render an attractive interface with Ajax loading, DHTML effects, and draggable windows.

In the interest of “adhering” people together, Micromenus exist as another option to make your Adhearsion VoIP applications more robust.

Integrating with a Web Application

Though Adhearsion by design can integrate with virtually any application, including PHP or Java Servlets, Ruby on Rails makes for a particularly powerful partner. Rails is a web development framework getting a lot of press lately for all the right reasons. Its developers use Ruby to its full potential, showing how meta-programming really does eliminate unnecessary developer work. Rails’ remarkable code clarity and application of the Don’t Repeat Yourself (DRY) principle served as a strong inspiration to the inception of Adhearsion as it exists today.

Starting with Adhearsion version 0.8.0, Adhearsion’s application directory drops in place atop an existing Rails application, sharing data automatically. If you have needs to develop a complex web interface to VoIP functionality, consider this deadly duo.

Using Java

Eyebrows around the world raised when Sun announced their hiring of the two core developers of the JRuby interpreter project, Charles Nutter and Thomas Enebo, in September 2006. JRuby is a Ruby interpreter written in Java instead of C. Because JRuby can compile parts of a Ruby application to Java bytecode, JRuby is actually outperforming the C implementation of Ruby 1.8 in many different benchmarks and promises to outperform Ruby 1.8 in all cases in the near future.

A Ruby application running in JRuby has the full benefit of not only Ruby libraries but any Java library as well. Running Adhearsion in JRuby brings the dumbfounding assortment of third-party Java libraries to PBX dialplan writing. If your corporate environment requires tight integration with other Java technologies, embedding Adhearsion in a J2EE stack may offer the flexibility needed.

More Information

For more information about the fast-moving Adhearsion community, including complete walkthroughs, see Adhearsion’s official web site at http://adhearsion.com, Adhearsion’s official blog at http://blog.adhearsion.com, the web site of Adhearsion’s parent consulting company http://codemecca.com, or for help learning Ruby, see http://jicksta.com.



[125] Contrast this with the Asterisk Gateway Interface (AGI), which allows Asterisk to launch an external program from the dialplan. The AGI and AMI interfaces are very much complimentary to each other.

[126] Carriage Return followed by Line Feed. This is popularly achieved by pressing the Enter key on the keyboard, but there are differences across various OS platforms and programming languages, so if you are having trouble with commands to the interface, it may be worth noting the exact character combination that is required. At the time of writing, Wikipedia had a respectable writeup on this concept (http://en.wikipedia.org/wiki/Newline).

[127] Customer Relationship Management (CRM) is an interface that companies use to help manage customer information and interaction.

[128] We would like to thank Jay Phillips for contributing the ideas and code for this section of the book.

Get Asterisk: The Future of Telephony, 2nd Edition now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.