Tutorial on Linux + Asterisk +MySQL + Java – part 3

This part of the tutorial begin the explanation of how to interact with Asterisk using Java.

After the introduction about Asterisk and MySQL, I think is right time to get our hands really dirty and begin talk of Java.
I will talk mostly of the use of the WONDERFUL Asterisk-java library. These guys are doing a great job and they keep going to support newer release of Asterisk.

There are basically three way to use Java with Asterisk:

  1. with CRUD operations on the Realtime database (as explained in the previous part);
  2. using AGI (Asterisk Gateway Interface) script, called from asterisk-java
  3. directly from asterisk-java.

In the previous post I have talked only of “realtime” management of the dialplan, but it may be used also for users, peers, and other configurations, with really slight modifications. So, for example, adding or removing records from “extensions” table will modify your current dialplan. But that’s basically just a mix of basic Java (CRUD operations) and Asterisk dialplan knowledge, so I won’t talk of it anymore.

“The Asterisk Gateway Interface is an interface for adding functionality to Asterisk with many different programming languages.” (quoted). Here you may find a tutorial about it – I could not do anything more than just copying thing from there.

Asterisk-java offers other two set of API, the Manager API and the Live API.
The “Manager API” provide and indirect way to send AMI commands to Asterisk, just like you would do with telnet login.
First, you have to enable it on Asterisk editing the “manager.conf” file; the following configuration allow access to “admin” user only from localhost on port 5038:

[general]
enabled = yes
port = 5038
bindaddr = 127.0.0.1
[admin]
secret = secret5
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.255
read = all,system,call,log,verbose,command,agent,user,config
write = all,system,call,log,verbose,command,agent,user,config

Test it with a telnet session (look here for the details – *really* a pain in the back, uh!?).
Now, let’s begin our work of developer.
First, let’s create an *asterisk-java* project. I am slowly moving to Maven, so I will use it to manage the dependencies.
This the asterisk-java artifact (actually, the only one needed for this tutorial):

<dependency>
	<groupId>org.asteriskjava</groupId>
	<artifactId>asterisk-java</artifactId>
	<version>1.0.0.M3</version>
</dependency>

and that’s the pom of my Maven project, automatically generated by Eclipse and with some modifications done by me:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>net.cardosi.asterisktutorial</groupId>
	<artifactId>AsteriskTutorial</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.0</version>
				<configuration>
					<source />
					<target />
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.asteriskjava</groupId>
			<artifactId>asterisk-java</artifactId>
			<version>1.0.0.M3</version>
			<exclusions>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-jms_1.1_spec</artifactId>
			<version>1.1</version>
		</dependency>
	</dependencies>
</project>

Take note of the exclusions. I think Maven is great *when* it works just out of the box but, alas, it is not always so 😦 . In the original asterisk-java dependencies there are some SUN artifacts unavailable from public repositories, so I have excluded them, and that’s fine, at least for our tutorial.
Now, let’s begin actual coding. First of all, you need a *connection* to Asterisk, and the following two lines:

  1. Instantiate a *factory* with connection parameters (the ones defined in the “manager.conf” file);
  2. Create a *connection* from the factory.
     ManagerConnectionFactory factory = new ManagerConnectionFactory(
				"localhost", "admin", "secret5");
     ManagerConnection managerConnection = factory.createManagerConnection();
     try {
	managerConnection.login();
     } catch (Exception e) {
     // Manage exception
     }

The above snippet is equivalent to the login inside a *telnet* connection.
In the following example we will tell Asterisk to call a sip client (with a callerId of “4000”, whose channel is “SIP/4000”) and then, if he accept the call, connect it to a given extension (the extension “600” in the “demo” context, at priority “1”).
First we build the required OriginateAction:

        OriginateAction originateAction = new OriginateAction();
	originateAction.setChannel("SIP/4000");
	originateAction.setCallerId("4000");
	originateAction.setTimeout(30000L); //the default timeout of 30 secs
	originateAction.setContext("demo");
	originateAction.setExten("600");
	originateAction.setPriority(1);

then we send this action through the opened connection, retrieving a *response* at the same time:

        try {
	   ManagerResponse originateResponse = managerConnection.sendAction(
					originateAction, 30000);
        } catch (Exception e) {
           // Manage exception
        }

The value set with

originateAction.setTimeout();

is the time that OriginateAction will wait for the channel to answer before throwing a TimeoutException, while the last parameter of the call

managerConnection.sendAction(originateAction, 30000);

is the time that ManagerConnection will wait for an answer from Asterisk before interrupting the action and throw a TimeoutException. Both times are in milliseconds.
If the command successfully complete before the two timeouts (and without any other errors), ManagerResponse.getResponse() will return “Success”, otherwise if one of the timeouts expire, a TimeoutException will be thrown.
OriginateAction is just one of the possible Actions that may be used with the Manager AMI. All the available ones are in the org.asteriskjava.manager.action package.

Here’s the full test class:

package net.cardosi.asterisk.ami;

import java.io.IOException;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerConnectionFactory;
import org.asteriskjava.manager.TimeoutException;
import org.asteriskjava.manager.action.OriginateAction;
import org.asteriskjava.manager.response.ManagerResponse;

public class AMITest {

	public static void main(String[] args) {
		// Retrieve the factory with connection parameters
		ManagerConnectionFactory factory = new ManagerConnectionFactory(
				"localhost", "admin", "secret5");
		// Retrieve the connection from the factory
		ManagerConnection managerConnection = factory.createManagerConnection();
		// Build the action to send
		OriginateAction originateAction = new OriginateAction();
		originateAction.setChannel("SIP/4000");
		originateAction.setCallerId("4000");
		originateAction.setTimeout(30000L); // this is also the default timeout
		originateAction.setContext("demo");
		originateAction.setExten("600");
		originateAction.setPriority(1);
		try {
			// login to Asterisk
			managerConnection.login();
			// sending the action and printing out the result;
			ManagerResponse originateResponse = managerConnection.sendAction(
					originateAction, 30000);
			System.out.println(originateResponse.getResponse());
		} catch (IOException e) {
			// Manage exception
		} catch (TimeoutException e) {
			// Manage exception
		} catch (Exception e) {
			// Manage exception
		}
	}
}

To successfully test all of that, please verify:

  1. you have a sip client correctly connected to your asterisk server;
  2. you can successfully connect to asterisk using the AMI;
  3. you need an extension you are redirecting your sip client to is “visible” for that peer.

And, well, that’s all for now. In the next part we will talk of the Live API: stay tuned!!!

Advertisements

2 thoughts on “Tutorial on Linux + Asterisk +MySQL + Java – part 3

  1. Thank you for great article,
    I am building simple outgoing IVR with Asterisk and asterisk-java I installed Xlite soft phone in two different computers (A and B) in same network and setup them on asterisk and I can call them successfully

    Here is my asterisk-java code

    public class PhoneUtility {

    private static ManagerConnection instanceManagerConnection;

    private static ManagerConnection getManagerConnectionInstance() {
    if (instanceManagerConnection == null) {
    ManagerConnectionFactory factory = new
    ManagerConnectionFactory(“192.132.0.01”, “admin”, “amp111”);
    instanceManagerConnection = factory.createManagerConnection();
    }
    return instanceManagerConnection;
    }

    public static boolean phoneCall() {
    try {
    ManagerConnection managerConnection = getManagerConnectionInstance();
    OriginateAction originateAction;
    ManagerResponse originateResponse;

    originateAction = new OriginateAction();
    originateAction.setChannel(“SIP/ivan”);
    originateAction.setCallerId(“1234”);
    originateAction.setContext(“ivr-ext”);
    originateAction.setExten(“1235”);
    originateAction.setPriority(new Integer(1));
    originateAction.setActionId(“2”);
    originateAction.setTimeout(300000l);
    originateAction.setAsync(new Boolean(false));

    // connect to Asterisk and log in
    managerConnection.login();

    AsteriskServerImpl asteriskServer = new AsteriskServerImpl(managerConnection);
    AsteriskChannel asteriskChannel = asteriskServer.originate(originateAction);

    // Play a prompt by text to speach

    Character dtmf = asteriskChannel.getDtmfSent();
    if (dtmf.equals(“1”)) {
    managerConnection.logoff();
    return true;
    } else {
    managerConnection.logoff();
    return false;
    }

    } catch (Exception e) {
    System.out.println(e);
    return false;
    }
    }
    }

    I execute the code (invoke phoneCall() ) in computer A to call computer B when the code is executed in computer A my soft phone rings in computer A first and I have to answer on soft phone computer A then computer B soft phone rings, How can I automatically open a channel for computer A through coding (I don’t want to have soft phone in computer A at all)

    Like

    • HI,
      I’ve the impression that your question is quite interesting, but I can not fully understand your goal. I mean, in this examples OriginateAction is used to connect a “client” to an extension – what happens on the other leg depends on how the target extension is configured. In your case, first part of the solution would be to call directly computer B, but then what do you want to achieve? You want your code to act as “sip client” ?

      Like

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