One of the Source Type options for a Dynamic Route is to use an AGI (Asterisk Gateway Interface) script. It’s a way to hand off call control from Asterisk dialplan to a script written in a conventional programming language, and then come back to dialplan. You can do quite a bit with plain Asterisk dialplan functions and applications, but you can’t do everything so the AGI is the way to fill in the gaps. Suppose you want to make an API call that returns results in json, which then must processed before the call destination can be determined. In such a case you might choose to use an AGI file with Dynamic Routes as there are no native Asterisk methods to process json (now there is !)…
A trivial example:
I want a dynamic route that calls an AGI file written in php. Using php is not an accident, since FreePBX is largely written in php, we can use the existing FreePBX libraries already in place. The AGI will just generate a random number between 1 and 4, and the dynroute will set a different FreePBX destination for each of these numbers. Using this I would be able randomly distribute inbound calls over a group of 4 extensions.
Step 1 - Create the AGI file
You need a plan text file with unix style EOLs (important!). The file should be owned by asterisk and needs to be executable. The name and location are arbitrary, but it’s conventional to save it in the agi directory with an agi extension::
# touch /var/lib/asterisk/agi-bin/dynroutes-test.agi
# chown asterisk:asterisk /var/lib/asterisk/agi-bin/dynroutes-test.agi
# chmod +x /var/lib/asterisk/agi-bin/dynroutes-test.agi
Edit the file with whatever unix editor you’re comfortable with:
# nano /var/lib/asterisk/agi-bin/dynroutes-test.agi
The file contents would look like this:
#!/usr/bin/php -q
<?php
// FreePBX Bootstrap environment (if needed)
include_once('/etc/asterisk/freepbx.conf');
// set up AGI env
include("phpagi.php"); // assumes this agi is saved in same dir as phpagi.php
$AGI = new AGI();
// log something in /var/log/asterisk/full
$AGI->verbose("dynroutes-test.agi starting up");
// generate random number between 1 and 4
$rand_choice = rand(1,4);
// log the random number result
$AGI->verbose("Random number generated ".$rand_choice);
// set an asterisk channel variable with the result
$AGI->set_variable("agi-random", $rand_choice);
// not needed for random number example, but demonstrates how to get values from Asterisk
// channel variables or functions into the AGI
$ampuser = $AGI->get_variable("AMPUSER");
if ($ampuser['result'] == 1) {
$AGI->verbose("Value of channel var AMPUSER: ".$ampuser['data']);
}
$calleridnum = $AGI->get_variable("CALLERID(number)");
if ($calleridnum['result'] == 1) {
$AGI->verbose("Value of function CALLERID(number): ".$calleridnum['data']);
}
exit;
The above AGI file is not too complex. It tells Asterisk we’re using php and it sets up the FreePBX bootstrap environment which is not used here, but in most cases it will be. It sets up the AGI class and logs some info to the Asterisk full log. A random number is generated, and very importantly it assigns the random number to an Asterisk channel variable called agi-random
. The value of that variable will be usable after the AGI completes as long as the channel remains up.
Step 2 - Create the Dynamic Route
Once the AGI exists, set up a dynroute in the conventional way with details that agree with the AGI file. For the Source Type, choose AGI and provide the path and name of the AGI file. In addition you must define an Asterisk channel variable, the value of which will be used to send the call to the defined destination. In this case, we’re using agi-random
, and we know the AGI will assign a value between 1 and 4. In the GUI it would look like this:
And that’s it for this simple example. The complexity is all in the AGI and the final result is assigned to a channel variable which is later referenced in dynroute dialplan to branch the call. It can be tricky to debug AGI files, so it’s useful to know that you can enable AGI verbose logging and get the output from the Asterisk console and full log. To enable:
agi set debut on
for the AGI file above, the debug output looks like this:
AGI Tx >> agi_network_script: /var/lib/asterisk/agi-bin/dynroutes-test.agi
<PJSIP/6006-00000003>AGI Tx >> agi_request: agi://127.0.0.1//var/lib/asterisk/agi-bin/dynroutes-test.agi
<PJSIP/6006-00000003>AGI Tx >> agi_channel: PJSIP/6006-00000003
<PJSIP/6006-00000003>AGI Tx >> agi_language: en
<PJSIP/6006-00000003>AGI Tx >> agi_type: PJSIP
<PJSIP/6006-00000003>AGI Tx >> agi_uniqueid: 1631583179.3
<PJSIP/6006-00000003>AGI Tx >> agi_version: 16.20.0
<PJSIP/6006-00000003>AGI Tx >> agi_callerid: 6006
<PJSIP/6006-00000003>AGI Tx >> agi_calleridname: P310
<PJSIP/6006-00000003>AGI Tx >> agi_callingpres: 0
<PJSIP/6006-00000003>AGI Tx >> agi_callingani2: 0
<PJSIP/6006-00000003>AGI Tx >> agi_callington: 0
<PJSIP/6006-00000003>AGI Tx >> agi_callingtns: 0
<PJSIP/6006-00000003>AGI Tx >> agi_dnid: 90210
<PJSIP/6006-00000003>AGI Tx >> agi_rdnis: unknown
<PJSIP/6006-00000003>AGI Tx >> agi_context: dynroute-11
<PJSIP/6006-00000003>AGI Tx >> agi_extension: s
<PJSIP/6006-00000003>AGI Tx >> agi_priority: 1
<PJSIP/6006-00000003>AGI Tx >> agi_enhanced: 0.0
<PJSIP/6006-00000003>AGI Tx >> agi_accountcode: boss
<PJSIP/6006-00000003>AGI Tx >> agi_threadid: 140361143826176
<PJSIP/6006-00000003>AGI Tx >>
<PJSIP/6006-00000003>AGI Rx << VERBOSE "dynroutes-test.agi starting up" 1
<PJSIP/6006-00000003>AGI Tx >> 200 result=1
<PJSIP/6006-00000003>AGI Rx << VERBOSE "Random number generated 1" 1
<PJSIP/6006-00000003>AGI Tx >> 200 result=1
<PJSIP/6006-00000003>AGI Rx << SET VARIABLE agi-random "1"
<PJSIP/6006-00000003>AGI Tx >> 200 result=1
<PJSIP/6006-00000003>AGI Tx >> HANGUP
As an aside, there is a waaaaaaaaaaay simpler way to achieve the goal of a random number between 1 and 4. That would be a dynroute with an Asterisk Variable ${RAND(1,4)}
. This entire post can be distilled down to those few characters.