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

This part of the tutorial will talk of the Asterisk-Java’ EventListener.

Beside the cool stuff we have previously seen about the Manager API and Live API, Asterisk-java offers some EventListeners to add more dynamic control over Asterisk behaviour. Some of this listeners belongs to the Manager API, and others to the Live API.
To use the Manager API EventListener, you may:

    implement the ManagerEventListener interface
    extend the AbstractManagerEventListener class

We will use the second method in this tutorial. To implement the listener, you have to:

  1. connect to the Asterisk server (as done in the previous parts)
  2. instantiate your class and add it as listener to the connection
  3. override/implement the method required to handle specific events; keep in mind that ManagerEventListener interface define only the
    onManagerEvent(ManagerEvent event)
    method (called when an event is received) while AbstractManagerEventListener already implements this method and defines all the required methods to manage every specific event (but this methods are empty and should be overridded)
  4. In this example, we will do all the connection setup in the constructor. Here’s the full code of the test class. Please note that this is just for demonstration, so forgive the *ugly* endless loop in the main method. Moreover, I have only overridden a couple of methods related to MeetMe join and leave events, but in the org.asteriskjava.manager.event package you may see all of them.

    package net.cardosi.asterisk.ami;
    
    import org.asteriskjava.manager.AbstractManagerEventListener;
    import org.asteriskjava.manager.ManagerConnection;
    import org.asteriskjava.manager.ManagerConnectionFactory;
    import org.asteriskjava.manager.event.MeetMeJoinEvent;
    import org.asteriskjava.manager.event.MeetMeLeaveEvent;
    
    public class AMIListenerTest extends AbstractManagerEventListener {
    
    	public AMIListenerTest() {
    		// Instantiate the factory
    		ManagerConnectionFactory factory = new ManagerConnectionFactory(
    				"localhost", "admin", "secret5");
    		// Retrieve the connection from the factory
    		ManagerConnection managerConnection = factory.createManagerConnection();
    		try {
    			// login to Asterisk
    			managerConnection.login();
    			// Add this object as listener to the connection
    			managerConnection.addEventListener(this);
    		} catch (Exception e) {
    			// Manage exception
    			e.printStackTrace();
    		}
    	}
    
    	@Override
    	protected void handleEvent(MeetMeJoinEvent event) {
    		System.out.println(event);
    	}
    
    	@Override
    	protected void handleEvent(MeetMeLeaveEvent event) {
    		System.out.println(event);
    	}
    
    	public static void main(String[] args) {
    		new AMIListenerTest();
    		while (true) {
    		}
    	}
    }
    

    To use the Live API EventListener, you may:

      implement the AsteriskServerListener interface
      extend the AbstractAsteriskServerListener class

    We will use the second method in this tutorial. The step are pretty similar as in the previous example, but now we will show you how to directly instantiate a DefaultAsteriskServer. With the Live API you can only listen for a small set of Asterisk events, but each of this event will provide a LiveObject to which, in turn, you may add a PropertyChangeListener to monitor what happen to it. The only method required to implement PropertyChangeListener is

    public void propertyChange(PropertyChangeEvent propertyChangeEvent).
    Our example class will both extend AbstractAsteriskServerListener and implement PropertyChangeListener:

    package net.cardosi.asterisk.live;
    
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import org.asteriskjava.live.AbstractAsteriskServerListener;
    import org.asteriskjava.live.AsteriskChannel;
    import org.asteriskjava.live.AsteriskQueueEntry;
    import org.asteriskjava.live.AsteriskServer;
    import org.asteriskjava.live.DefaultAsteriskServer;
    import org.asteriskjava.live.MeetMeUser;
    import org.asteriskjava.live.internal.AsteriskAgentImpl;
    
    public class LiveListenerTest extends AbstractAsteriskServerListener implements
    		PropertyChangeListener {
    
    	public LiveListenerTest() {
    		AsteriskServer asteriskServer = new DefaultAsteriskServer("localhost",   "admin", "secret5");
    		asteriskServer.addAsteriskServerListener(this);
    	}
    
    	public void onNewAsteriskChannel(AsteriskChannel channelParam) {
    		System.out.println(channelParam);
    		channelParam.addPropertyChangeListener(this);
    	}
    
    	public void onNewMeetMeUser(MeetMeUser userParam) {
    		System.out.println(userParam);
    		userParam.addPropertyChangeListener(this);
    	}
    
    	public void onNewAgent(AsteriskAgentImpl agentParam) {
    		System.out.println(agentParam);
    		agentParam.addPropertyChangeListener(this);
    	}
    
    	public void onNewQueueEntry(AsteriskQueueEntry entryParam) {
    		System.out.println(entryParam);
    		entryParam.addPropertyChangeListener(this);
    	}
    
    	public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
    		System.out.println(propertyChangeEvent);
    	}
    
    	public static void main(String[] args) {
    		new LiveListenerTest();
    		while (true) {
    		}
    	}
    }
    

    “A “PropertyChange” event gets delivered whenever a bean changes a “bound” or “constrained” property. A PropertyChangeEvent object is sent as an argument to the PropertyChangeListener and VetoableChangeListener methods.” (quoted). So, whenever the state of the LiveObject change, you may be informed of what and how changed. If you try the above code, for example connecting a client to a MeetMe conference, you will see all the events and notifications that will be triggered.

    … and that’s all, folks!!!
    I hope you enjoyed this tutorial.
    Bye

    Advertisements

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

This part of the tutorial keep going with the explanation of the Asterisk-Java’ Live API.

We concluded the previous part of the tutorial talking of Manager API. Now it is time to talk of the Live API.
This API provide an *abstraction* layer over the Manager API, making available *objects* representing Asterisk’ components, instead of directly send commands to the AMI. Some of this *objects* are AsteriskChannel (it represents a channel inside Asterisk), AsteriskServer (the Asterisk server itself) and so on. You may find them inside the org.asteriskjava.live package.
In the following example we tell asterisk to call a (connected) SIP client and, if it answer, redirect it to a specific extension. First of all we have to login to the AMI, as we did in the previous part:

        ManagerConnectionFactory factory = new ManagerConnectionFactory(
				"localhost", "admin", "secret5");
	// Retrieve the connection from the factory
	ManagerConnection managerConnection = factory.createManagerConnection();
	try {
		// login to Asterisk
		managerConnection.login();
         ...

then we instantiate an AsteriskServerImpl that “represent” the Asterisk server:

AsteriskServerImpl asteriskServer = new AsteriskServerImpl(managerConnection);

Now, we want to be sure to call a client actually connected, so:

  1. first, we retrieve the list or configured peers
  2. iterate over them and select the first (if any) is currently connected
  3. if no peer is connected, the method return
  4. otherwise, we retrieve the peer’ channel
  5. and then call it and, eventually, redirect it to a specific context/extension/priority
        // Retrieve the list of configured peers
	List peerEntries = asteriskServer.getPeerEntries();
	PeerEntryEvent peerToCall = null;
        // Iterate over peers
	for (PeerEntryEvent peerEntry : peerEntries) {
		String status = peerEntry.getStatus();
                // Select the first one connected and exit the loop
		if (status != null && status.contains("OK")) {
		         peerToCall = peerEntry;
                         break;
		}
	}
        // If no peer is connected exit from method
	if (peerToCall == null) {
		return;
	}
        // Build the channel name
	String channelName = peerToCall.getChannelType();
	channelName += "/" + peerToCall.getObjectName();
        // Call the client and, eventually, redirect it
	asteriskServer.originateToExtension(channelName, "default", "8600", 1, 10000);

originateToExtension is just one of the methods that AsteriskServerImpl offers. As a side note, it throws an Exception if the “originate” action cannot be sent to the Asterisk server or if the channel name is unavailable. A nice thing is that this method returns an AsteriskChannel that may be used for funny stuff, like for example send a DTMF to the peer:

         AsteriskChannel asteriskChannel = asteriskServer.originateToExtension(channelName, "default", "8600", 1, 10000);
	asteriskChannel.playDtmf("1");

In my dialplan 8600@default is a MeetMe conference – I am using this for the example so to be sure that the channel is still active when we send the DTMF.
As I have already told you at the beginning of the tutorials (or maybe not, I’m getting older), I am not an Asterisk GURU, but here I would just put a quick checklist to verify that you have a correct MeetMe configuration (thanks Jorge for your suggestion):

  1. Meetme depends on dahdi; so dahdi module should be loaded (on linux, check with lsmod | grep dahdi); moreover, dahdi channels must be owned by the user that *actually* run asterisk – to be clear, I start asterisk as root but the asterisk process is owned by “asterisk” user (ps aux | grep asterisk); so, all /dev/dahdi “devices” (and the directory itself) must be owned by “asterisk” user;
  2. inside meetme.conf you just have to put a line like “conf => (number of conference, ex. 1234);
  3. of course, you have to load MeetMe module on Asterisk (you can check it for example from console with “meetme list” command; it actually shows only active conferences, so it is normal you have an empty return);
  4. you have to create a dialplan extensions that point to the meetme conference (ex. exten => 8600,1,Meetme(1234));
  5. verify that everything is working with a sip phone calling the extension (in the example, 8600) – you should be able to join the conference (and now the conference should appear with the “meetme list” command).

And here’s the complete code to use:

package net.cardosi.asterisk.live;

import java.util.List;
import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.internal.AsteriskServerImpl;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerConnectionFactory;
import org.asteriskjava.manager.event.PeerEntryEvent;

public class LiveTest {

	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();
		try {
			// login to Asterisk
			managerConnection.login();
			// Instantiate a new AsteriskServer
			AsteriskServerImpl asteriskServer = new AsteriskServerImpl(
					managerConnection);
			// Retrieve the list of configured peers
			List peerEntries =                                asteriskServer.getPeerEntries();
			PeerEntryEvent peerToCall = null;
			// Iterate over peers
			for (PeerEntryEvent peerEntry : peerEntries) {
				String status = peerEntry.getStatus();
				// Select the first one connected and exit the loop
				if (status != null && status.contains("OK")) {
					peerToCall = peerEntry;
					break;
				}
			}
			// If no peer is connected exit from method
			if (peerToCall == null) {
				return;
			}
			String channelName = peerToCall.getChannelType();
			channelName += "/" + peerToCall.getObjectName();
			System.out.println("Calling " + channelName);
			AsteriskChannel asteriskChannel = 
                           asteriskServer.originateToExtension(channelName, "default",   "8600", 1, 10000);
			Thread.sleep(10000);
			System.out.println("Playing '1' on " + channelName);
			asteriskChannel.playDtmf("1");
		} catch (Exception e) {
			// Manage exception
			e.printStackTrace();
		}
	}
}

To test the code, you have to verify the settings like in the previous part. Moreover, you have to configure an extension in your dialplan that keep the channel active (MeetMe, ConfBridge, ParkedCall).
And that’s all for now. In the next part we will have some fun with EventListeners. Don’t miss that!!! Bye

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

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

This part of the tutorial explain how to implement Asterisk’ Realtime functionality with MySQL.

After the brief introduction about LAMJ and the Linux + Asterisk + MySQL + Java, let’s begin to do some configuration.
I’ll not explain the general rules for Asterisk setup on a Linux box, here’s some good starting point:
Asterisk Documentation
Quick Start Guide (pdf)

With the file-based configuration (i.e. all the modifications done to the *.conf files) you setup a static configuration of your PBX – it may be right for you, if you don’t need to change something frequently, mostly in the dialplan.
BUT there is also the chance that you have to do it or, even more funny, you have to write a software that does this for you following the request of an end user.
So, REALTIME to the rescue.
The Realtime function (to be used inside your extensions.conf) allows you to configure your dialplan with data coming from a “RealTime repository” (that is, for me, a database); more interesting is that the modification you are doing in your database are instantly taken by Asterisk (after all, there must be a reason for the “Realtime” term).
One thing to clarify, anyway, is that you may also obtain “realtime” configuration only using Java (we will see that in later post) but the configuration will not persist (unless, after a very heavy dinner, a lot of drinks, and a sleepless night full of nightmares, you decided to programmatically edit the .conf files!!!).

Now, since the LAMJ imply the MySQL support, I will explain only this part of the configuration.
To cut a long story short, you have to:

  1. Have the res_config_mysql.so (it is part of the “asterisk add-ons” – don’t ask me why; explaining how to get or build it is part of a lot of other tutorials);
  2. Create the database and grant privileges to a given user (in this tutorial “asterisk” will be used as database name, user name, and user password: exceptionally secure, uh?! 🙂 )
  3. Create the dialplan table (“extensions” in this tutorial):

    CREATE TABLE `extensions` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `context` varchar(20) NOT NULL DEFAULT '',
    `exten` varchar(20) NOT NULL DEFAULT '',
    `priority` varchar(10) NOT NULL,
    `app` varchar(20) NOT NULL DEFAULT '',
    `appdata` varchar(128) NOT NULL DEFAULT '',
    PRIMARY KEY (`context`,`exten`,`priority`),
    KEY `id` (`id`)
    );
  4. Edit the “res_config_mysql.conf” file with the connection parameters to the database, beside a specific [section-name] (“asterisk-section” in this tutorial)

    [asterisk-section]
    dbhost = 127.0.0.1
    dbname = asterisk
    dbuser = asterisk
    dbpass = asterisk
    dbport = 3306
    dbsock = /var/run/mysqld/mysqld.sock
    dbcharset = latin1
    requirements=warn
  5. Add to the “extconfig.conf” file a line with the format
    <family> => <realtime driver>,<[section-name]>[,<table>]
    to specify that for a given configuration the given repository will be used; in our tutorial we will focus on dialplan configuration (whose family is “extensions”) with MySQL (whose realtime driver is “mysql”), like this:
    extensions => mysql,asterisk-section,extensions
    WARN: this is different from old versions of asterisk, where instead of the [section-name] you have to put the database name (that would have been “asterisk” in this tutorial); I can’t tell exactly when this has changed, but in 1.6 it was different;
  6. Add a “switch” directive in “extensions.conf” (the dialplan configuration file):

    switch => Realtime/conference@extensions

    please note that “conference” in the above line is the “context” to be loaded, and it must match the value you put in the “context” column inside the “extensions” table; you may have more than one switch, one for each “context” you want to be managed in realtime;
  7. Be sure to load the “res_config_mysql” module, and the others required for realtime to work; this can be done inside “modules.conf” file with this simple directive:

    autoload=yes

If everything is correct, when you reload or restart asterisk you should see in the console a line containing “Registered Config Engine mysql”; if not, check everything from beginning.
Using “dialplan show” in the asterisk CLI you should also have the entry:

Alt. Switch => 'Realtime/conference@extensions'
Check your “extensions.conf” if you don’t see it.
Now, as far as I can tell there is no direct way to see the “realtime” extensions from the CLI: you have to test it with a sip client. The following .sql snippet define an “echo” extension at 6878@conference:

INSERT INTO extensions (context, exten, priority, app, appdata) VALUES ("conference", "6878", "1", "Playback", "demo-echotest");
INSERT INTO extensions (context, exten, priority, app, appdata) VALUES ("conference", "6878", "2", "Echo", "");
INSERT INTO extensions (context, exten, priority, app, appdata) VALUES ("conference", "6878", "3", "Playback", "demo-echodone");
INSERT INTO extensions (context, exten, priority, app, appdata) VALUES ("conference", "6878", "4", "Hangup", "");

After inserted this records in the database (no need to reload – that’s realtime magic!) dialing “6878” from your sip client should enter you in echo test. A couple of things to keep in mind:

  1. “demo-echotest” and “demo-echodone” are audio files that you should have in your “sound” directory
  2. the sip peer should be registered with the context containing the “switch” directive, otherwise he won’t be able to access the realtime-configured context.

Well, I hope everything is clear enough for you to go on. Again, I am not diving too much in asterisk basics because the main focus of this tutorial will be hit in the following parts regarding java. Anyway, you are more than welcome to post your questions or to point me to the silly mistakes I may have done.
In the next part we will begin with actual Java coding: don’t miss it!!!

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

This part of the tutorial is an introduction about the combined use of Asterisk, Java and MySQL on a Linux box.

In the internet era Linux has a very important role for the famous LAMP stack: Linux + Apache + MySQL + PHP.

But I am not a web-type; I had some of the greatest fun working with VoIP/PBX, more specifically with Asterisk, so I decided to share my experience, and I named the environment I have worked with LAMJ, which stands for Linux + Asterisk + MySQL + Java.
I won’t talk about Linux and MySQL, but I will give a very brief introduction about PBX.

PBX is the acronym of Private Branch Exchange. It could refer to a hardware device or to a software running on a computer. Asterisk is one of the most diffused software PBX, but there are also others, like Callweaver and FreeSWITCH (well, FreeSWITCH is not exactly a PBX, it’s author describe it as a soft switch in his comparison with Asterisk).
VoIP stands for Voice Over IP.
Technically VoIP and PBX are not dependent one to the other. A PBX could be connected only to a PSTN or only to a VoIP network. The third option, the one that I found most interesting, is that a PBX could be connected to both a PSTN and a VoIP network, acting as a sort of bridge between the twos.
This is not to be confused with PSTN/VoIP Gateway, where the communication is forwarded from PSTN to VoIP (and the other way around).
A software PBX could be connected to communication channel(s) in one or more of the following ways:

  1. with the computer’s internet connection
  2. with an internal card (Digium, Sangoma, Rhino, etc)
  3. with a Channel bank
  4. with a Gateway (internal or from an external provider) to which it is connected via ethernet/internet.

Currently there are different VoIP protocols, the most known being SIP, IAX, and H.323.
Probably SIP protocol is the most widely used, at least for connection between end-user device/software and PBX, even if it may require some tweaking to overcome NAT issues, while IAX maybe has better performance, but it is used mostly for inter-PBX communication.
Please keep in mind that I am a developer, not a network/VoIP engineer, so feel free to correct me if I wrote something wrong in the above introduction.

In the next part we will cover the Realtime configuration. C YA!!!