AGI Scripting with Ruby

AGI stands for Asterisk Gateway Interface. It is very similar to CGI (common gateway interface) which is one of the first forms of web development.

AGI allows for Asterisk to communicate in real-time with an external process. Asterisk will send output to the external process through “Standard Out” (STDOUT), and will listen for input on “Standard In” (STDIN). STDOUT and STDIN are what you use whenever you are interacting with the command line. When we type “ls” in the terminal we are sending in that command to the terminal process through its STDIN, and when the terminal shows us the list of files it is sending that list to our screen through its STDOUT.

Calling AGI Scripts

To call an AGI script from the Asterisk dialplan you use the AGI command

exten => s,1,Answer();
exten => s,n,AGI(/home/ck987/asterisk_agi/agi_test.rb);

By default Asterisk looks for the AGI script in the agi-bin (/var/lib/asterisk/agi-bin). You can place them anywhere but it is probably a good idea to put them in your asterisk_agi directory.

Debugging

In the Asterisk administration console you can type: “agi set debug on” to enable AGI debugging.  “agi set debug off” will turn off AGI debugging.

Basic AGI Scripting in Ruby

#!/usr/bin/ruby

require 'rubygems'
require 'ruby-agi'

agi = AGI.new

# start agi scripting
agi.stream_file("vm-extension")
result = agi.wait_for_digit(-1)	# wait forever
if result.digit
        agi.say_number(result.digit)
end

#end of	agi script

Upload, Test and Run

Save the above script to a file, let’s call it “easy.rb” for now. Using Fetch or another SFTP application upload the script to the “asterisk_agi” in your home directory. Log into the server using SSH and navigate to the directory containing the agi scripts (cd asterisk_agi) and execute the command required to make the file executable (chmod 755 easy.rb).

To test that the file runs without error, type the following:

./easy.rb

This should start the execution of the file, if it doesn’t there is an error that you need to fix. The application should wait indefinitely for input (which it is expecting from Asterisk through STDIN). You can simulate this by hitting return a couple of times. You should see some semblance of the commands that are sent to Asterisk via STDOUT.

Ruby-agi documentation

More Fun Get the current weather!

#!/usr/bin/ruby

require 'rubygems'
require 'ruby-agi'		#for Asterisk AGI
require 'net/http'		#for http connections
require 'rexml/document'	#for parsing XML

agi = AGI.new

# for a complete list of US cities, go to
# http://www.weather.gov/xml/current_obs/
weatherURL = []
weatherURL << "http://w1.weather.gov/xml/current_obs/KNYC.xml" #NYC
weatherURL << "http://w1.weather.gov/xml/current_obs/KJFK.xml" #JFK
weatherURL << "http://w1.weather.gov/xml/current_obs/KART.xml" #Watertown, NY
weatherURL << "http://w1.weather.gov/xml/current_obs/KBGM.xml" #Binghamton
weatherURL << "http://w1.weather.gov/xml/current_obs/KBUF.xml" #Buffalo
weatherURL << "http://w1.weather.gov/xml/current_obs/KDKK.xml" #Chautauqua County
weatherURL << "http://w1.weather.gov/xml/current_obs/KDSV.xml" #Dansville
weatherURL << "http://w1.weather.gov/xml/current_obs/KELM.xml" #Corning, NY
weatherURL << "http://w1.weather.gov/xml/current_obs/KHPN.xml" #Westchester
weatherURL << "http://w1.weather.gov/xml/current_obs/KFRG.xml" #Farmingdale, NY

while true #loop forever
	agi.stream_file("vm-extension")
	result = agi.wait_for_digit(-1)  # -1 = wait forever
	digit = result.digit
	if (!digit)
		agi.noop("no button received.  quitting AGI script.")
		exit #quit ruby
	end
	url = weatherURL[digit.to_i]
	# get the XML data as a string
	xml_data = Net::HTTP.get_response(URI.parse(url)).body
	# extract event information
	doc = REXML::Document.new(xml_data)
	temp_f = doc.get_text('current_observation/temp_f')

	if temp_f
		current_temp = temp_f
	else
		agi.noop("couldn't find temp in xml. quitting.")
		continue = false
		exit #quit ruby
	end
	#say the temp and ask for another digit
	agi.say_number(current_temp)
end