Asterisk
Asterisk Asterisk
Contents

Asterisk - The Open Source VoIP PBX

Previous Page Next Page
 
Asterisk: The Future of Telephony
Table of Contents
Copyright
Foreword
Preface
Audience
Organization
Software
Conventions Used in This Book
Using Code Examples
Safari® Enabled
How to Contact Us
Acknowledgments
Chapter 1.  A Telephony Revolution
Section 1.1.  VoIP: Bridging the Gap Between Traditional Telephony and Network Telephony
Section 1.2.  Massive Change Requires Flexible Technology
Section 1.3.  Asterisk: The Hacker's PBX
Section 1.4.  Asterisk: The Professional's PBX
Section 1.5.  The Asterisk Community
Section 1.6.  The Business Case
Section 1.7.  This Book
Chapter 2.  Preparing a System for Asterisk
Section 2.1.  Server Hardware Selection
Section 2.2.  Environment
Section 2.3.  Telephony Hardware
Section 2.4.  Types of Phone
Section 2.5.  Linux Considerations
Section 2.6.  Conclusion
Chapter 3.  Installing Asterisk
Section 3.1.  What Packages Do I Need?
Section 3.2.  Obtaining the Source Code
Section 3.3.  Compiling Zaptel
Section 3.4.  Compiling libpri
Section 3.5.  Compiling Asterisk
Section 3.6.  Installing Additional Prompts
Section 3.7.  Updating Your Source Code
Section 3.8.  Common Compiling Issues
Section 3.9.  Loading Zaptel Modules
Section 3.10.  Loading libpri
Section 3.11.  Loading Asterisk
Section 3.12.  Directories Used by Asterisk
Section 3.13.  Conclusion
Chapter 4.  Initial Configuration of Asterisk
Section 4.1.  What Do I Really Need?
Section 4.2.  Working with Interface Configuration Files
Section 4.3.  FXO and FXS Channels
Section 4.4.  Configuring an FXO Channel
Section 4.5.  Configuring an FXS Channel
Section 4.6.  Configuring SIP
Section 4.7.  Configuring Inbound IAX Connections
Section 4.8.  Configuring Outbound IAX Connections
Section 4.9.  Debugging
Section 4.10.  Conclusion
Chapter 5.  Dialplan Basics
Section 5.1.  Dialplan Syntax
Section 5.2.  A Simple Dialplan
Section 5.3.  Adding Logic to the Dialplan
Section 5.4.  Conclusion
Chapter 6.  More Dialplan Concepts
Section 6.1.  Expressions and Variable Manipulation
Section 6.2.  Dialplan Functions
Section 6.3.  Conditional Branching
Section 6.4.  Voicemail
Section 6.5.  Macros
Section 6.6.  Using the Asterisk Database (AstDB)
Section 6.7.  Handy Asterisk Features
Section 6.8.  Conclusion
Chapter 7.  Understanding Telephony
Section 7.1.  Analog Telephony
Section 7.2.  Digital Telephony
Section 7.3.  The Digital Circuit-Switched Telephone Network
Section 7.4.  Packet-Switched Networks
Section 7.5.  Conclusion
Chapter 8.  Protocols for VoIP
Section 8.1.  The Need for VoIP Protocols
Section 8.2.  VoIP Protocols
Section 8.3.  Codecs
Section 8.4.  Quality of Service
Section 8.5.  Echo
Section 8.6.  Asterisk and VoIP
Section 8.7.  Conclusion
Chapter 9.  The Asterisk Gateway Interface (AGI)
Section 9.1.  Fundamentals of AGI Communication
Section 9.2.  Writing AGI Scripts in Perl
Section 9.3.  Creating AGI Scripts in PHP
Section 9.4.  Writing AGI Scripts in Python
Section 9.5.  Debugging in AGI
Section 9.6.  Conclusion
Chapter 10.  Asterisk for the Über-Geek
Section 10.1.  Festival
Section 10.2.  Call Detail Recording
Section 10.3.  Customizing System Prompts
Section 10.4.  Manager
Section 10.5.  Call Files
Section 10.6.  DUNDi
Section 10.7.  Conclusion
Chapter 11.  Asterisk: The Future of Telephony
Section 11.1.  The Problems with Traditional Telephony
Section 11.2.  Paradigm Shift
Section 11.3.  The Promise of Open Source Telephony
Section 11.4.  The Future of Asterisk
Appendix A.  VoIP Channels
Section A.1.  IAX
Section A.2.  SIP
Appendix B.  Application Reference
AbsoluteTimeout( )
AddQueueMember( )
ADSIProg( )
AgentCallbackLogin( )
AgentLogin( )
AgentMonitorOutgoing( )
AGI( )
AlarmReceiver( )
Answer( )
AppendCDRUserField( )
Authenticate( )
Background( )
BackgroundDetect( )
Busy( )
CallingPres( )
ChangeMonitor( )
ChanIsAvail( )
CheckGroup( )
Congestion( )
ControlPlayback( )
Curl( )
Cut( )
DateTime( )
DBdel( )
DBdeltree( )
DBget( )
DBput( )
DeadAGI( )
Dial( )
DigitTimeout( )
Directory( )
DISA( )
DumpChan( )
DUNDiLookup( )
EAGI( )
Echo( )
EndWhile( )
ENUMLookup( )
Eval( )
Exec( )
ExecIf( )
FastAGI( )
Festival( )
Flash( )
ForkCDR( )
GetCPEID( )
GetGroupCount( )
GetGroupMatchCount( )
Goto( )
GotoIf( )
GotoIfTime( )
Hangup( )
HasNewVoicemail( )
HasVoicemail( )
IAX2Provision( )
ImportVar( )
LookupBlacklist( )
LookupCIDName( )
Macro( )
MailboxExists( )
Math( )
MeetMe( )
MeetMeAdmin( )
MeetMeCount( )
Milliwatt( )
Monitor( )
MP3Player( )
MusicOnHold( )
NBScat( )
NoCDR( )
NoOp( )
Park( )
ParkAndAnnounce( )
ParkedCall( )
PauseQueueMember( )
Playback( )
Playtones( )
Prefix( )
PrivacyManager( )
Progress( )
Queue( )
Random( )
Read( )
RealTime
RealTimeUpdate( )
Record( )
RemoveQueueMember( )
ResetCDR( )
ResponseTimeout( )
RetryDial( )
Ringing( )
SayAlpha( )
SayDigits( )
SayNumber( )
SayPhonetic( )
SayUnixTime( )
SendDTMF( )
SendImage( )
SendText( )
SendURL( )
Set( )
SetAccount( )
SetAMAFlags( )
SetCallerID( )
SetCallerPres( )
SetCDRUserField( )
SetCIDName( )
SetCIDNum( )
SetGlobalVar( )
SetGroup( )
SetLanguage( )
SetMusicOnHold( )
SetRDNIS( )
SetVar( )
SIPAddHeader( )
SIPDtmfMode( )
SIPGetHeader( )
SoftHangup( )
StopMonitor( )
StopPlaytones( )
StripLSD( )
StripMSD( )
SubString( )
Suffix( )
System( )
Transfer( )
TrySystem( )
TXTCIDName( )
UnpauseQueueMember( )
UserEvent( )
Verbose( )
VMAuthenticate( )
VoiceMail( )
VoiceMailMain( )
Wait( )
WaitExten( )
WaitForRing( )
WaitForSilence( )
WaitMusicOnHold( )
While( )
Zapateller( )
ZapBarge( )
ZapRAS( )
ZapScan( )
Appendix C.  AGI Reference
ANSWER
CHANNEL STATUS
DATABASE DEL
DATABASE DELTREE
DATABASE GET
DATABASE PUT
EXEC
GET DATA
GET FULL VARIABLE
GET OPTION
GET VARIABLE
HANGUP
NOOP
RECEIVE CHAR
RECORD FILE
SAY ALPHA
SAY DATE
SAY DATETIME
SAY DIGITS
SAY NUMBER
SAY PHONETIC
SAY TIME
SEND IMAGE
SEND TEXT
SET AUTOHANGUP
SET CALLERID
SET CONTEXT
SET EXTENSION
SET MUSIC ON
SET PRIORITY
SET VARIABLE
STREAM FILE
TDD MODE
VERBOSE
WAIT FOR DIGIT
Appendix D.  Configuration Files
Section D.1.  modules.conf
Section D.2.  adsi.conf
Section D.3.  adtranvofr.conf
Section D.4.  agents.conf
Section D.5.  alarmreceiver.conf
Section D.6.  alsa.conf
Section D.7.  asterisk.conf
Section D.8.  cdr.conf
Section D.9.  cdr_manager.conf
Section D.10.  cdr_odbc.conf
Section D.11.  cdr_pgsql.conf
Section D.12.  cdr_tds.conf
Section D.13.  codecs.conf
Section D.14.  dnsmgr.conf
Section D.15.  dundi.conf
Section D.16.  enum.conf
Section D.17.  extconfig.conf
Section D.18.  extensions.conf
Section D.19.  features.conf
Section D.20.  festival.conf
Section D.21.  iax.conf
Section D.22.  iaxprov.conf
Section D.23.  indications.conf
Section D.24.  logger.conf
Section D.25.  manager.conf
Section D.26.  meetme.conf
Section D.27.  mgcp.conf
Section D.28.  modem.conf
Section D.29.  musiconhold.conf
Section D.30.  osp.conf
Section D.31.  oss.conf
Section D.32.  phone.conf
Section D.33.  privacy.conf
Section D.34.  queues.conf
Section D.35.  res_odbc.conf
Section D.36.  rpt.conf
Section D.37.  rtp.conf
Section D.38.  sip.conf
Section D.39.  sip_notify.conf
Section D.40.  skinny.conf
Section D.41.  voicemail.conf
Section D.42.  vpb.conf
Section D.43.  zapata.conf
Section D.44.  zaptel.conf
Appendix E.  Asterisk Command-Line Interface Reference
!
abort halt
Section E.1.  add
Section E.2.  agi
Section E.3.  database
Section E.4.  iax2
Section E.5.  indication
Section E.6.  logger
Section E.7.  meetme
Section E.8.  pri
Section E.9.  remove
Section E.10.  restart
Section E.11.  set
Section E.12.  show
Section E.13.  sip
Section E.14.  stop
Section E.15.  zap
Colophon
About the Authors
Colophon
Index
SYMBOL
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
Previous Page
Next Page

9.2. Writing AGI Scripts in Perl

Asterisk comes with a sample AGI script called agi-test.agi. Let's step through the file while we cover the core concepts of AGI programming. While this particular script is written in Perl, please remember that your own AGI programs may be written in almost any programming language. Just to prove it, we're going to cover AGI programming in a couple of other languages later in the chapter.

Let's get started! We'll look at each section of the code in turn, and describe what it does.

    #!/usr/bin/perl

This line tells the system that this particular script is written in Perl, so it should use the Perl interpreter to execute the script. If you've done much Linux or Unix scripting, this line should be familiar to you. This line assumes, of course, that your Perl binary is located in the /usr/bin/ directory. Change this to match the location of your Perl interpreter.

    use strict;

use strict tells Perl to act, well, strict about possible programming errors, such as undeclared variables. While not absolutely necessary, enabling this will help you avoid common programming pitfalls.

    $|=1;

This line tells Perl not to buffer its outputin other words, that it should write any data immediately, instead of waiting for a block of data before outputting it. You'll see this as a recurrent theme throughout the chapter.

You should always use unbuffered output when writing AGI scripts. Otherwise, your AGI may not work as expected, because Asterisk may be waiting for the output of your program, while your program thinks it has sent the output to Asterisk and is waiting for a response.


    # Set up some variables
    my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;

Here, we set up four variables. The first is a hash called AGI, which is used to store the variables that Asterisk passes to our script at the beginning of the AGI session. The next three are scalar values, used to count the total number of tests, the number of failed tests, and the number of passed tests, respectively.

    while(<STDIN>) {
            chomp;
            last unless length($_);
            if (/^agi_(\w+)\:\s+(.*)$/) {
                    $AGI{$1} = $2;
            }
    }

As we explained earlier, Asterisk sends a group of variables to the AGI program at startup. This loop simply takes all of these variables and stores them in the hash named AGI. They can be used later in the program or simply ignored, but they should always be read from STDIN before continuing on with the logic of the program.

    print STDERR "AGI Environment Dump:\n";
    foreach my $i (sort keys %AGI) {
            print STDERR " -- $i = $AGI{$i}\n";
    }

This loop simply writes each of the values that we stored in the AGI hash to STDERR. This is useful for debugging the AGI script, as STDERR is printed to the Asterisk console.[*]

[*] Actually, to the first spawned Asterisk console (i.e., the first instance of Asterisk called with the -c or -r option). If safe_asterisk was used to start Asterisk, the first Asterisk console will be on TTY9, which means that you will not be able to view AGI errors remotely.

    sub checkresult {
            my ($res) = @_;
            my $retval;
            $tests++;
            chomp $res;
            if ($res =~ /^200/) {
                    $res =~ /result=(-?\d+)/;
                    if (!length($1)) {
                            print STDERR "FAIL ($res)\n";
                            $fail++;
                    } else {
                            print STDERR "PASS ($1)\n";
                            $pass++;
                    }
            } else {
                    print STDERR "FAIL (unexpected result '$res')\n";
                    $fail++;
            }

This subroutine reads in the result of an AGI command from Asterisk and decodes the result to determine whether the command passes or fails.

Now that the preliminaries are out of the way, we can get to the core logic of the AGI script.

    print STDERR "1.  Testing 'sendfile'...";
    print "STREAM FILE beep \"\"\n";
    my $result = <STDIN>;
    &checkresult($result);

This first test shows how to use the STREAM FILE command. The STREAM FILE command tells Asterisk to play a sound file to the caller, just as the Background( ) application does. In this case, we're telling Asterisk to play a file called beep.gsm.[]

[] Asterisk automatically selects the best format, based on translation cost and availability, so the file extension is never used in the function.

You will notice that the second argument is passed by putting in a set of double quotes, escaped by backslashes. Without the double quotes to indicate the second argument, this command does not work correctly.

You must pass all required arguments to the AGI commands. If you want to skip a required argument, you must send empty quotes (properly escaped in your particular programming language), as shown above. If you don't pass the required number of arguments, your AGI script will not work.

You should also make sure you pass a line feed (the \n on the end of the print statement) at the end of the command.


After sending the STREAM FILE command, this test reads the result from STDIN and calls the checkresult subroutine to determine if Asterisk was able to play the file. The STREAM FILE command takes three arguments, two of which are required:

  • The name of the sound file to play back

  • The digits that may interrupt the playback

  • The position at which to start playing the sound, specified in number of samples (optional)

In short, this test told Asterisk to play back the file named beep.gsm, and then checked the result to make sure the command was successfully executed by Asterisk.

    print STDERR "2.  Testing 'sendtext'...";
    print "SEND TEXT \"hello world\"\n";
    my $result = <STDIN>;
    &checkresult($result);

This test shows us how to call the SEND TEXT command, which is similar to the SendText( ) application. This command will send the specified text to the caller, if the caller's channel type supports the sending of text.

The SEND TEXT command takes one argument: the text to send to the channel. If the text contains spaces (as in the example above), the argument should be encapsulated with quotes, so that Asterisk will know that the entire text string is a single argument to the command. Again, notice that the quotation marks are escaped, as they must be sent to Asterisk, not used to terminate the string in Perl.

    print STDERR "3.  Testing 'sendimage'...";
    print "SEND IMAGE asterisk-image\n";
    my $result = <STDIN>;
    &checkresult($result);

This test calls the SEND IMAGE command, which is similar to the SendImage( ) application. Its single argument is the name of an image file to send to the caller. As with the SEND TEXT command, this command works only if the calling channel supports the reception of images.

    print STDERR "4.  Testing 'saynumber'...";
    print "SAY NUMBER 192837465 \"\"\n";
    my $result = <STDIN>;
    &checkresult($result);

This test sends Asterisk the SAY NUMBER command. This command behaves identically to the SayNumber( ) dialplan application. It takes two arguments:

  • The number to say

  • The digits that may interrupt the command

Again, since we're not passing in any digits as the second argument, we need to pass in an empty set of quotes.

    print STDERR "5.  Testing 'waitdtmf'...";
    print "WAIT FOR DIGIT 1000\n";
    my $result = <STDIN>;
    &checkresult($result);

This test shows the WAIT FOR DIGIT command. This command waits the specified number of milliseconds for the caller to enter a DTMF digit. If you want the command to wait indefinitely for a digit, use -1 as the timeout. This application returns the decimal ASCII value of the digit that was pressed.

    print STDERR "6.  Testing 'record'...";
    print "RECORD FILE testagi gsm 1234 3000\n";
    my $result = <STDIN>;
    &checkresult($result);

This section of code shows us the RECORD FILE command. This command is used to record the call audio, similar to the Record( ) dialplan application. RECORD FILE takes seven arguments, the last three of which are optional:

  • The filename of the recorded file.

  • The format in which to record the audio.

  • The digits that may interrupt the recording.

  • The timeout (maximum recording time) in milliseconds, or -1 for no timeout.

  • The number of samples to skip before starting the recording (optional).

  • The word BEEP, if you'd like Asterisk to beep before the recording starts (optional).

  • The number of seconds before Asterisk decides that the user is done with the recording and returns, even though the timeout hasn't been reached and no DTMF digits have been entered (optional). This argument must be preceded by s=.

In this particular case, we're recording a file called testagi (in the GSM format), with any of the DTMF digits 1 through 4 terminating the recording, and a maximum recording time of 3,000 milliseconds.

    print STDERR "6a.  Testing 'record' playback...";
    print "STREAM FILE testagi \"\"\n";
    my $result = <STDIN>;
    &checkresult($result);

The second part of this test plays back the audio that was recorded earlier, using the STREAM FILE command. We've already covered STREAM FILE, so this section of code needs no further explanation.

    print STDERR "================== Complete ======================\n";
    print STDERR "$tests tests completed, $pass passed, $fail failed\n";
    print STDERR "==================================================\n";

At the end of the AGI script, a summary of the tests is printed to STDERR, which should end up on the Asterisk console.

In summary, you should remember the following when writing AGI programs in Perl:

  • Turn on strict language checking with the use strict command.[*]

    [*] This advice probably applies to any Perl program you might write, especially if you're new to Perl.

  • Turn off output buffering by setting $|=1.

  • Data from Asterisk is received using a while(<STDIN>) loop.

  • Write values with the print command.

  • Use the print STDERR command to write debug information to the Asterisk console.

9.2.1. The Perl AGI Library

If you are interesting in building your own AGI scripts in Perl, you may want to check out the Asterisk::AGI Perl module written by James Golovich, which is located at http://asterisk.gnuinter.net. The Asterisk::AGI module makes it even easier to write AGI scripts in Perl.


Previous Page
Next Page
Asterisk