<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Folks,<br>
<br>
7 months ago, I made some modifications to Asterisk to allow AGI
commands to be passed via the Manager API. The advantage over AGI and
FastAGI is the reduced number of sockets to monitor on the controlling
machine. If there are 200 channels open on 10 machines that are all
being managed from a single control machine, that's 2,000 open sockets
(a lot for a kernel to handle) and lots of threads listening to those
open sockets. By sending all the commands (AGI and Manager) through a
single socket, there are fewer open sockets and a single place to
manage all the interactions with Asterisk.<br>
<br>
I've had systems in production for the last 7 months running the MAGI
(Manager AGI) code. There hasn't been a single failure or problem.
I've got Java code running on my application server managing the
Asterisk instances. All works like a charm.<br>
<br>
I've had a couple of requests for the code. I figure I'll make it
available to everyone. Maybe if enough people use it, we'll be able to
get the mods into the main Asterisk distribution.<br>
<br>
You can download a tarball of Asterisk (it's the source from about a
week ago with the MAGI mods) plus Java code that allows you to control
Asterisk. In addition, I'm enclosing a sample Java class that answers
the call and plays "12345" to the caller.<br>
<br>
You can download the tarball from:<br>
<a class="moz-txt-link-freetext" href="http://www.projectsinmotion.com/ast_with_magi.tgz">http://www.projectsinmotion.com/ast_with_magi.tgz</a><br>
<br>
To access, MAGI, put the following in your dialplan:<br>
<tt><br>
exten => 4157380662,1,MAGI(DOSTUFF|${EXTEN})<br>
</tt><br>
The code that follows is example Java code.<br>
<br>
I hope folks out there find the code valuable. If you've got any
questions, please let me know. If you've got enhancements or
suggestions for improvement, I'd love to see them.<br>
<br>
Thanks,<br>
<br>
David<br>
<br>
<tt><b>Place this method someplace so that the connection to Asterisk
gets
initialized and the right factories vend the right instances. I have
this code executed as part of a class static {} in a class that's
loaded when my app server starts.</b><br>
<br>
<br>
private static void startAsterisk() {
<br>
// fire off the Asterisk manager
<br>
AstManager.setChannelFactory(new AstManager.ICreateChannel() {
<br>
public AstChannel create(String chanNum, String chanId,
<br>
AstConnection conn) {
<br>
return new MyAstChannel(chanNum, chanId,
(MyAstConnection) conn);
<br>
}
<br>
});
<br>
<br>
AstManager.setConnectionFactory(new
AstManager.ICreateConnection() {
<br>
public AstConnection create(String host, int port,
<br>
AstConnection.IUserNamePassword pwd) throws
IOException {
<br>
return new MyAstConnection(host, port, pwd);
<br>
}
<br>
<br>
});
<br>
<br>
Thread t = new Thread(new Runnable() {
<br>
public void run() {
<br>
AstManager man = new AstManager();
<br>
man.start(new AstManager.IConnected() {
<br>
public void connectedToAsterisk(AstConnection conn)
{
<br>
System.out.println("Dude... we're connected");
<br>
}
<br>
<br>
public void failedToConnect() {
<br>
run();
<br>
}
<br>
}, "localhost", 5038, new
AstConnection.IUserNamePassword() {
<br>
public String getUsername() {
<br>
return "foo";
<br>
}
<br>
<br>
public String getPassword() {
<br>
return "bar";
<br>
}
<br>
});
<br>
}
<br>
});
<br>
t.start();
<br>
}
<br>
<br>
<b>MyAstChannel:
This class handles the current channel. The key thing is it subclasses
runNAExec which is called when the MAGI command is called in Asterisk
on the given channel. It answers the line, waits 2 seconds, and then
runs "SAY DIGITS" with 12345.</b><br>
<br>
/*
<br>
* Created on Aug 11, 2004
<br>
*
<br>
* (c) 2004-2005 David Pollak
<br>
*/
<br>
package net.maxvox.mvasterisk;
<br>
<br>
import java.net.URLDecoder;
<br>
import java.sql.SQLException;
<br>
import java.util.Date;
<br>
import java.util.HashMap;
<br>
<br>
<br>
import net.maxvox.asterisk.AstChannel;
<br>
import net.maxvox.asterisk.INameValuePair;
<br>
import net.maxvox.asterisk.IServerCommand;
<br>
import net.maxvox.asterisk.IVRUtils;
<br>
import net.maxvox.asterisk.NameValuePairImpl;
<br>
import net.maxvox.asterisk.ServerCommandImpl;
<br>
<br>
<br>
/**
<br>
* @author dpp
<br>
*
<br>
* Represents a channel in the Asterisk
<br>
*/
<br>
public class MyAstChannel extends AstChannel {
<br>
<br>
public MyAstChannel(String name, String uniqueId, MyAstConnection
conn) {
<br>
super(name, uniqueId, conn);
<br>
}
<br>
<br>
<br>
protected void runNAExec(HashMap<String, String> params,
<br>
HashMap<String, String> results) {
<br>
super.runNAExec(params, results);
<br>
<br>
this.answer(new IServerCommand.ICommandStringCallback() {
<br>
public void complete(int code, IServerCommand command,
String result) {
<br>
try {
<br>
Thread.sleep(2000);
<br>
} catch (InterruptedException ie) {
<br>
// ignore
<br>
}
<br>
sayDigits("12345");
<br>
}
<br>
<br>
});
<br>
}
<br>
<br>
}
<br>
<br>
<b>MyAstConnection:
There's 1 instance of this class per Asterisk server connection. No
real reason to subclass it, but I did anyway... :-)</b><br>
<br>
/*
<br>
* Created on Aug 9, 2004
<br>
*
<br>
* (c) 2004-2005 David Pollak
<br>
*/
<br>
<br>
package net.maxvox.mvasterisk;
<br>
<br>
import java.io.BufferedReader;
<br>
import java.io.File;
<br>
import java.io.FileWriter;
<br>
import java.io.IOException;
<br>
import java.io.InputStream;
<br>
import java.io.InputStreamReader;
<br>
import java.io.OutputStream;
<br>
import java.io.PrintWriter;
<br>
import java.net.InetAddress;
<br>
import java.net.InetSocketAddress;
<br>
import java.net.Socket;
<br>
import java.nio.ByteBuffer;
<br>
import java.nio.CharBuffer;
<br>
import java.nio.channels.SelectableChannel;
<br>
import java.nio.channels.SocketChannel;
<br>
import java.nio.charset.Charset;
<br>
import java.sql.SQLException;
<br>
import java.util.ArrayList;
<br>
import java.util.HashMap;
<br>
import java.util.Iterator;
<br>
import java.util.LinkedList;
<br>
import java.util.Set;
<br>
<br>
import org.jendo.base.SmartBaseObject;
<br>
import org.jendo.base.SmartException;
<br>
import org.jendo.util.Diag;
<br>
<br>
import net.maxvox.asterisk.AstChannel;
<br>
import net.maxvox.asterisk.AstConnection;
<br>
import net.maxvox.asterisk.INameValuePair;
<br>
import net.maxvox.asterisk.IServerCommand;
<br>
import net.maxvox.asterisk.NameValuePairImpl;
<br>
import net.maxvox.asterisk.SelectChannelMonitor;
<br>
import net.maxvox.asterisk.ServerCommandImpl;
<br>
import net.maxvox.asterisk.AstConnection.IUserNamePassword;
<br>
<br>
/**
<br>
* @author dpp
<br>
*
<br>
* Connection to an Asterisk Server's Manager API
<br>
*/
<br>
public class MYAstConnection extends AstConnection {
<br>
public MyAstConnection(String host, int port, IUserNamePassword pwd)
<br>
throws IOException {
<br>
super(host, port, pwd);
<br>
}
<br>
public static MyAstConnection instance() {
<br>
AstConnection conn = AstConnection.instance();
<br>
if (conn != null && conn instanceof MyAstConnection) {
<br>
return (MyAstConnection) conn;
<br>
}
<br>
return null;
<br>
}
<br>
<br>
}
<br>
<br>
</tt>
<br>
</body>
</html>