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.4. Writing AGI Scripts in Python

The AGI script we'll be writing in Python , called "The Subtraction Game," was inspired by a Perl program written by Ed Guy and discussed by him at the 2004 AstriCon conference. Ed described his enthusiasm for the power and simplicity of Asterisk when he found he could write a quick Perl script to help his young daughter improve her math skills.

Since we've already written a Perl program using AGI, and Ed has already written the math program in Perl, we figured we'd take a stab at it in Python!

Let's go through our Python script.

    #!/usr/bin/python

This line tells the system to run this script in the Python interpreter. For small scripts, you may consider adding the -u option to this line, which will run Python in unbuffered mode. This is not recommended, however, for larger or frequently used AGI scripts, as it can affect system performance.

    import sys
    import re
    import time
    import random

Here, we import several libraries that we'll be using in our AGI script.

    # Read and ignore AGI environment (read until blank line)

    env = {}
    tests = 0;

    while 1:
       line = sys.stdin.readline( ).strip( )

       if line == '':
          break
       key,data = line.split(':')
       if key[:4] <> 'agi_':
          #skip input that doesn't begin with agi_
          sys.stderr.write("Did not work!\n");
          sys.stderr.flush( )
          continue
       key = key.strip( )
       data = data.strip( )
       if key <> '':
          env[key] = data

    sys.stderr.write("AGI Environment Dump:\n");
    sys.stderr.flush( )
    for key in env.keys( ):
       sys.stderr.write(" -- %s = %s\n" % (key, env[key]))
       sys.stderr.flush( )

This section of code reads in the variables that are passed to our script from Asterisk, and saves them into a dictionary named env. These values are then written to STDERR for debugging purposes.

    def checkresult (params):
       params = params.rstrip( )
       if re.search('^200',params):
          result = re.search('result=(\d+)',params)
          if (not result):
             sys.stderr.write("FAIL ('%s')\n" % params)
             sys.stderr.flush( )
             return -1
          else:
             result = result.group(1)
             #debug("Result:%s Params:%s" % (result, params))
             sys.stderr.write("PASS (%s)\n" % result)
             sys.stderr.flush( )
             return result
       else:
          sys.stderr.write("FAIL (unexpected result '%s')\n" % params)
          sys.stderr.flush( )
          return -2

The checkresult function is almost identical in purpose to the checkresult subroutine in the sample Perl AGI script we covered earlier in the chapter. It reads in the result of an Asterisk command, parses the answer, and reports whether or not the command was successful.

    def sayit (params):
       sys.stderr.write("STREAM FILE %s \"\"\n" % str(params))
       sys.stderr.flush( )
       sys.stdout.write("STREAM FILE %s \"\"\n" % str(params))
       sys.stdout.flush( )
       result = sys.stdin.readline( ).strip( )
       checkresult(result)

The sayit function is a simple wrapper around the STREAM FILE command.

    def saynumber (params):
       sys.stderr.write("SAY NUMBER %s \"\"\n" % params)
       sys.stderr.flush( )
       sys.stdout.write("SAY NUMBER %s \"\"\n" % params)
       sys.stdout.flush( )
       result = sys.stdin.readline( ).strip( )
       checkresult(result)

The saynumber function is a simple wrapper around the SAY NUMBER command.

    def getnumber (prompt, timelimit, digcount):
       sys.stderr.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount))
       sys.stderr.flush( )
       sys.stdout.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount))
       sys.stdout.flush( )
       result = sys.stdin.readline( ).strip( )
       result = checkresult(result)
       sys.stderr.write("digits are %s\n" % result)
       sys.stderr.flush( )
       if result:
          return result
       else:
          result = -1

The getnumber function calls the GET DATA command to get DTMF input from the caller. It is used in our program to get the caller's answers to the subtraction problems.

    limit=20
    digitcount=2
    score=0
    count=0
    ttanswer=5000

Here, we initialize a few variables that we'll be using in our program.

    starttime = time.time( )
    t = time.time( ) - starttime

In these lines we set the starttime variable to the current time and initialize t to zero. We'll use the t variable to keep track of the number of seconds that have elapsed since the AGI script was started.

    sayit("subtraction-game-welcome")

Next, we welcome the caller to the subtraction game.

    while ( t < 180 ):

       big = random.randint(0,limit+1)
       big += 10
       subt= random.randint(0,big)
       ans = big - subt
       count += 1

       #give problem:
       sayit("subtraction-game-next");
       saynumber(big);
       sayit("minus");
       saynumber(subt);
       res = getnumber("equals",ttanswer,digitcount);

       if (int(res) == ans) :
          score+=1
          sayit("subtraction-game-good");
       else :
          sayit("subtraction-game-wrong");
          saynumber(ans);

       t = time.time( ) - starttime

This is the heart of the AGI script. We loop through this section of code and give subtraction problems to the caller until 180 seconds have elapsed. Near the top of the loop, we calculate two random numbers and their difference. We then present the problem to the caller, and read in the caller's response. If the caller answers incorrectly, we give the correct answer.

    pct = float(score)/float(count)*100;
    sys.stderr.write("Percentage correct is %d\n" % pct)
    sys.stderr.flush( )

    sayit("subtraction-game-timesup")
    saynumber(score)
    sayit("subtraction-game-right")
    saynumber(count)
    sayit("subtraction-game-pct")
    saynumber(pct)

After the users are done answering the subtraction problems, they are given their scores.

As you have seen, the basics you should remember when writing AGI scripts in Python are:

  • Flush the output buffer after every write. This will ensure that your AGI program won't hang while Asterisk is waiting for the buffer to fill and Python is waiting for the response from Asterisk.

  • Read data from Asterisk with the sys.stdin.readline command.

  • Write commands to Asterisk with the sys.stdout.write command. Don't forget to call sys.stdout.flush after writing.

9.4.1. The Python AGI Library

If you are planning on writing lot of Python AGI code, you may want to check out Karl Putland's Python module, Pyst. You can find it at http://www.sourceforge.net/projects/pyst/.


Previous Page
Next Page
Asterisk