In this post I will cover how to write a simple Auto Dialer in Java.
It is necessary to be familiar with Asterisk, the way its dial plan Works
and also to have some knowledge of Java programming language.
With some modifications, you could do many different things using this
code as base:
- Set a cron job to execute your program in a certain moment of the day, for instance, as a clock alarm.
- Broadcast an audio message to a list of phone numbers.
- Conduct a marketing campaign or survey, ask questions that people could answer by pressing a digit.
- To load your list of numbers from a database list.
These are just some ideas, but there are many possibilities.
Asterisk call files
These are files, that basically, contain the instructions to achieve a
phonecall.
Once set in the right directory, they are detected by Asterisk service
which then executes the instructions written within them.
Strategy
Our strategy will be to write a Java application to produce this files
into a temporary directory, then copy or move them to directory /var/spool/asterisk/outgoing/,
so Asterisk can process them.
This is actually very simple, but we can add more functionality later to
be able to cover our particular need.
Syntax for a call file to
reproduce a message (or execute an application)
- Specify where and how to call
- Channel: <channel>: Channel to use for the call.
- CallerID: "name" <number> Caller ID, Please note: It may not work if you do not respect the format: CallerID: "Some Name" <1234>
- MaxRetries: <number> Number of retries before failing (not including the initial attempt, e.g. 0 = total of 1 attempt to make the call). Default is 0.
- RetryTime: <number> Seconds between retries, Don't hammer an unavailable phone. Default is 300 (5 min).
- WaitTime: <number> Seconds to wait for an answer. Default is 45.
- Account: Set the account code to use.
- If the call answers, connect it here:
- Context: <context-name> Context in extensions.conf
- Extension: <ext> Extension definition in extensions.conf
- Priority: <priority> Priority of extension to start with
- Set: Set a variable for use in the extension logic (example: file1=/tmp/to ); in Asterisk 1.0.x use 'SetVar' instead of 'Set'
- Application: Asterisk Application to run (use instead of specifiying context, extension and priority)
- Data: The options to be passed to application
- New (?) in Asterisk 1.4
- Set: Can now also write to dialplan functions like CDR()
- AlwaysDelete: Yes/No - If the file's modification time is in the future, the call file will not be deleted
- Archive: Yes/No - Move to subdir "outgoing_done" with "Status: value", where value can be Completed, Expired or Failed.
This means we have two options: 1) to reference a context/extension/priority
that is already defined don our extensions.conf, or 2) to invoke an Asterisk
application through AGI specifying its parameters.
Prerequisites
to test this Demo.
- An Ubuntu or CentOS installation running Asterisk.
- If we want to test PSTN calls, we should have a configured trunk to enable so.
- An audio file located at /var/lib/asterisk/sounds/ called mensaje.gsm with some test message which will be reproduced to people who answer our phone calls.
- JDK installed (you can verify if it is installed using the command java –version, in case it is not, you should install it).
- We need to create the directory /var/spool/asterisk/tmp/
Now, we create a file called AutoDialerDemo.java.
As I mentioned before, we should have the directory /var/spool/asterisk/tmp/ and the SO user who is going to execute the application should have enough privileges to write on it (better if super user to avoid more complexities).
//Directory where the files will be added
private static final String TMP_DIR_PATH = "/var/spool/asterisk/tmp";
We will use a file called prueba.cfg, which should be located on the
same directory of our file AutoDialerDemo.java.
//When
executng the application, we pass as parameter the name of the configuration
file (for isntance prueba.cfg)
generarLlamadas(args[0]);
The content of our file prueba.cfg would look like this, but with your data:
app.proveedor=YourTrunk/Provider
app.numero_0=1234ANumberAsYourProviderExpectsIt
app.numero_1=1234OtherNumberAsYourProviderExpectsIt
generarLlamadas(args[0]);
The content of our file prueba.cfg would look like this, but with your data:
app.proveedor=YourTrunk/Provider
app.numero_0=1234ANumberAsYourProviderExpectsIt
app.numero_1=1234OtherNumberAsYourProviderExpectsIt
app.numero_2=1159393260807InMyCase
...
app.numero_9=1234LastNumberAsYourProviderExpectsIt
Finally, we create one call file for each number on the list, and we structure it using the data specified on the file prueba.cfg:
//Assign the file name
file = new File(tmpDir, filename + ".call");
writer = new BufferedWriter(new FileWriter(file));
String text = "";
//Speify the channel, in this case, the phone call we will made
text = "Channel: SIP/" + proveedor + "/" + numero;
writer.write(text);
writer.newLine();
System.out.println(text);
//We will retry one time if the original try is not connected
text = "MaxRetries: 1";
writer.write(text);
writer.newLine();
//We will retry 60 seconds after the original try
text = "RetryTime: 60";
writer.write(text);
writer.newLine();
//We will wait 30 seconds for our call to be answered
text = "WaitTime: 30";
writer.write(text);
writer.newLine();
//Once it is answered, we will reproduce our message
text = "Application: Playback";
writer.write(text);
writer.newLine();
//The audio of the message to be reproduced is stored into file mensaje.gsm
//Remember this should be on directory /var/lib/asterisk/sounds
text = "Data: mensaje";
writer.write(text);
writer.newLine();
app.numero_9=1234LastNumberAsYourProviderExpectsIt
Finally, we create one call file for each number on the list, and we structure it using the data specified on the file prueba.cfg:
//Assign the file name
file = new File(tmpDir, filename + ".call");
writer = new BufferedWriter(new FileWriter(file));
String text = "";
//Speify the channel, in this case, the phone call we will made
text = "Channel: SIP/" + proveedor + "/" + numero;
writer.write(text);
writer.newLine();
System.out.println(text);
//We will retry one time if the original try is not connected
text = "MaxRetries: 1";
writer.write(text);
writer.newLine();
//We will retry 60 seconds after the original try
text = "RetryTime: 60";
writer.write(text);
writer.newLine();
//We will wait 30 seconds for our call to be answered
text = "WaitTime: 30";
writer.write(text);
writer.newLine();
//Once it is answered, we will reproduce our message
text = "Application: Playback";
writer.write(text);
writer.newLine();
//The audio of the message to be reproduced is stored into file mensaje.gsm
//Remember this should be on directory /var/lib/asterisk/sounds
text = "Data: mensaje";
writer.write(text);
writer.newLine();
We copy the generated file from directory /var/spool/asterisk/tmp/
to directory /var/spool/asterisk/outogoing/. We made it this way to prevent
asterisk to process an incomplete file:
//We give Asterisk user permissions over our file
Runtime.getRuntime().exec("chown asterisk:asterisk /var/spool/asterisk/tmp/" + filename + ".call");
//We then move it to the directory where asterisk will process it
Runtime.getRuntime().exec("mv /var/spool/asterisk/tmp/" + filename + ".call /var/spool/asterisk/outgoing/" + filename + ".call");
Now we compile the java file:
$ javac AutoDialerDemo.java
$ javac AutoDialerDemo.java
And we will obtain the file AutoDialerDemo.class. After this, assuming the file prueba.cfg is located on the same directory, and the information within it is correct, we execute:
$ java AutoDialerDemo prueba.cfg
I recommend to have another terminal window connected to Asterisk CLI,
so you can see what happens once we
execute our application. In case of troubleshooting this could be very useful.
¡Good luch with those auto generated calls! Just try not to execute them
while your buddies on the phone list are sleeping zzz.
Great information, I really like all your post.
ResponderEliminarPredictive Auto Dialer