Tag Archives: manager

Analog remix part 3: some Perl CGI to route the call

Part 3 of the analog remix ties it all together. We need a way for Tropo to tell Asterisk to transfer the call, since we’re not going to use SIP REFER. A simple Perl CGI that connects to Asterisk Manager Interface (AMI) will do the trick.

I’m sticking with old-school Perl for this one because I really like Ryan Bullock’s Asterisk::AMI modules. His code is easy to use and he keeps it up to date.

Referring back to part 2, you can see where the curl function calls tropo.cgi (the Perl script below) with parameters f=xfer (the only function for now), callid=the SIP Call-ID, and dest=the number the caller requested. The Perl script finds the Call-ID by iterating through the channel list, finding one that’s connected to Tropo, and then checking the Call-ID to make sure it’s the exact one. (You could have more than one channel open to Tropo.) Once it finds that, it transfers the second leg of that call, which is the caller. Output is to STDERR so that I can review the transaction in the Apache error log.

Updated 12/19/2010: This line

my $link = $currchan->{'Link'} || $currchan->{'BridgedChannel'};

is updated to use either the key returned by Asterisk 1.4 (“Link”) or by later versions (“BridgedChannel”) in the channel listing.

The code:

#!/usr/bin/perl

use strict;
use Asterisk::AMI::Common;
use CGI;
use URI::Escape;

select(STDERR);
local $| = 1;
select(STDOUT);
local $| = 1;

my $cgi = CGI->new;
my $func = $cgi->param('f');
my $callid = uri_unescape($cgi->param('callid'));
my $dest = $cgi->param('dest');

print $cgi->header("text/plain");

if(defined $func) {
  if($func eq "xfer") {
    if(defined $dest && $dest ne "") {
      my $ami = Asterisk::AMI::Common->new (PeerAddr => 'localhost',
                                    PeerPort => '5038',
                                    Username => 'USERNAME',
                                    Secret => 'PASSWORD',
                                    Events => 'off',
                                    on_error => &errorHandler
                                   )
      or die "Unable to connect to Asterisk Manager.n";

      my $channels = $ami->channels;
      if (defined($channels)) {
        foreach my $channel (keys %{$channels}) {
          my $currchan = %{$channels}->{"$channel"};
          if ($channel =~ m/tropo.com/) { # find channels connected to Tropo
            my $currchan_callid = $ami->get_var($channel, "SIPCALLID");
            if ($currchan_callid == $callid) { # make sure it's the right call,
              print STDERR "Channel $channel"; # identified by Call-ID
              print STDERR "Callid $callid";

              my $link = $currchan->{'Link'} || $currchan->{'BridgedChannel'};
              if (defined($link)) { # this is the initiating leg of the call
                my $transfer = $ami->transfer($link, $dest, "from-internal");
                if (defined($transfer)) {
                  if ($transfer == 1) {
                    print STDERR "Tropo successfully transferred $link to $dest.";
                  } else {
                    print STDERR "Tropo FAILED to transfer $link to $dest.";
                  }
                } else {
                  print STDERR "System error performing transfer.";
                }
              } else {
                print STDERR "Local channel leg not found.";
              }
            }
          }
        }
      } else {
        print STDERR "Could not get channel list from Asterisk manager.";
      }
      $ami->disconnect; # close Manager connection
    } else {
      print STDERR "xfer requested but no dest specified.";
    }
  } else {
    print STDERR "Invalid function sent in CGI.";
  }
} else {
  print STDERR "No function sent in CGI.";
}

print "Done.n";
exit;

#### Functions ####

sub errorHandler {  # A fatal error occurred
  my ($amiobj, $errmsg) = @_;
  print STDERR "AMI Fatal error: $errmsgn";
  exit 1;
}

Summary

Starting with part 1, configure a hot line or warm line for your old analog device to automatically ring an extension on your system. You’ll define that extension as the SIP URI to the Tropo application you made in part 2. The Tropo application, in turn, will connect back to your Asterisk server running web services (Apache) with a CGI that can take the input and connect to the Asterisk Manager Interface and transfer your call. Simple! 🙂