Quick overview of (Asterisk) AGI using Python


I’m learning about AGI today, and naturally I decided to attack it with python and no library.

If you’re confused about what AGI can do, don’t be. As it’s name implies it’s not a terribly different concept from CGI, except for the fact that two way communication is extremely pivotal in AGI. Like CGI, It’s all stdin and stdout.

A crude explanation of AGI is a something like this:

  • Step 1. Your dialplan invokes an AGI script
  • Step 2. Your AGI script reads stdin until it finds an empty line, to get all the AGI variables (you needn’t get this confused with os.getenv — they’re all coming in through stdn in the format “property: value\n”)
  • Step (X). Your AGI script sends an AGI command through stdout
  • Step (X+1). Your AGI script reads a line on stdin to obtain the response and result from its last command (this is also how you allow your script wait for its command to complete).
  • Step (X+2). Do something with that result?
  • Finally, Your script exits.

This is what I came up with, the script simply announces your caller ID (as a number), plays a beep, and then accepts up to 5 digits, and then plays those digits back to you (as a number, again).

Extension (somewhere in extensions*.conf…):

exten => 234234,1,Answer
exten => 234234,n,AGI(andy.agi)
exten => 234234,2,Hangup

/var/lib/asterisk/agi-bin/andy.agi (+x):

#!/usr/bin/python
import sys,os,datetime

def log(msg):
    open('/tmp/andy.agi.log','ab+',512).write(
        "%s: %s\n"%(datetime.datetime.now(),msg)
    )

def get():
    res = sys.stdin.readline()
    log(res)
    res = res.strip()
    response,delim,result=res.partition(' ')
    result=result.split('=')[1].strip()
    result,delim,data = result.partition(' ')
    return response,result,data

def send(data):
    log(data)
    sys.stdout.write("%s \n"%data)
    sys.stdout.flush()

def getDigits(count=1):
    i=0
    digits=''
    digit = None
    while (i<count):
        i += 1
        send("WAIT FOR DIGIT 5000")
        digit = get()[1]
        if digit == "0" or digit == "-1":
            break;
        if digit:
            digits += str(int(digit)-48)
    return digits

AGIENV={}

env = ""
while(env != "\n"):

    env = sys.stdin.readline()
    log("Looping: env = \"%s\""%env)
    envdata =  env.split(":")
    if len(envdata)==2:
        AGIENV[envdata[0].strip()]=envdata[1].strip()

log(AGIENV)
log ("os.environ: %s"%os.environ)

send("SAY NUMBER %s \"\""%AGIENV['agi_callerid'])
res = get()
send("STREAM FILE beep \"\"");
res = get()
send('SAY NUMBER %s "*#"\n'%getDigits(5))
res = get()

Of course this is completely non-realworld. Anything going to log() was just for me to get a handle on what was actually happening, but I left it in here in case somebody else was going through the same thing. “tail -f” before or during the call gives you the best overview of what’s happening.

Other things

Arguments:

You can pass arguments to your AGI script from the dialplan.  Arguments are separated by the | character.

Environmental variables:

There are certain environmental variables you can access through getenv(), but they tend to be more related to asterisk and not so much AGI specifically.

There’s a great reference of agi variables, env variables, and agi commands available at voip-info, see my sources below.

I should point out that I would also likely be using something like pyst for my real-world applications, but I think it’s important to know all the nitty-gritty before jumping into a valuable library.

Sources:

Details:
  • Asterisk 1.6.2.18
  • Python 2.5
  • Debian 5
About these ads

About andyortlieb

I often find myself figuring out some niche oddities, only to find myself stuck on those same problems a year later due to my wide yet thin activity in certain topics related to my career and hobbies. This blog is where I document these nuances (or nuisances) to ease my pain the second time around, and hopefully that of some other fellow desperate internet scouts.
This entry was posted in Uncategorized. Bookmark the permalink.

2 Responses to Quick overview of (Asterisk) AGI using Python

  1. andyortlieb says:

    Using Pyst…..

    # Import the pyst module “agi”
    from asterisk import agi

    # Initializing this class reads stdin for those variables
    myapp = agi.AGI()

    # Use a system recording to prompt the caller to enter some digits.
    data = myapp.get_data(‘custom/Testrecording’)

    # (Do something with the data)
    # In this case, just play the digits back to the user
    myapp.say_digits(mydata)

  2. Randy Lust says:

    Do you have any more pyst examples for Asterisk that you can share? I am looking for an example that will dial out and play a message!
    Thanks Nice site!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s