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
Advertisements

About andyortlieb

I've been a tinkerer and a lazy ideologist since I gained my first personal computer in 1989. I have an aversion to formal education and I prefer to learn things by experimentation. That is not a brag, it has not been a particularly helpful set of traits. My primary goals are to increase my safety, pleasure and usefulness as I work to build and modify technologies that will bring those same attributes to the masses irrespective of government. This is the documentation of my attempt at that journey.
This entry was posted in Uncategorized. Bookmark the permalink.

3 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!

    • andyortlieb says:

      Hey Randy, sorry I never got back to you. I think by the time you commented I was already out of the telephony business, though since then I’ve been pulled back in. it’s inescapable apparently. If you still want a simple outbound dialer take a look at Summit or Twilio–but watch out for FTC regulations.

      You have some great photos on your website.

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