jueves, 27 de agosto de 2015

¿Por que le llaman "Arturito" al mueble del oficina?

La mayoría de nosotros conoce aquel mueble de oficina, una cajonera, de dos o tres cajones, que de altura estará un poco más arriba de la rodilla, generalmente con ruedas. La mayoría de las personas se refieren a este mueble como "Arturito".
Y, ¿por qué le llaman así?
Realicé una encuesta rápida, que concluyó con lo que yo mismo sospechaba. Este mueble recibe su nombre por una cierta similitud con el personaje de Star Wars, R2D2, que en inglés se pronunciaría algo así como ar tu di tu. De allí que en el Ecuador, por confusión respecto al nombre del personaje (muchos jurarán que de verdad el personaje se llama Arturito), y luego, por una supuesta similitud: ambos son de metal, ambos tienen ruedas, ambos son pequeños... tenemos que al mueble de oficina le llaman Arturito (ar tu di tu).

viernes, 31 de agosto de 2012

How to make an Auto Dialer for your Asterisk (This an English translation of my previous post)



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    
     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();


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

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.
 
You can download the source file here
AutoDialerDemo.java.

¡Good luch with those auto generated calls! Just try not to execute them while your buddies on the phone list are sleeping zzz.

martes, 28 de agosto de 2012

Como hacer un Autodialer para Asterisk


Hola, antes de continuar, quiero decirles que he trabajado en una nueva forma de hacer el marcador automático, con intertefaz web, en fin, mucho mejor. Pueden encontrar más información aquí.

En esta entrada les explicaré como escribir un Auto Dialer sencillo en Java. 
Como requerimiento, es necesario estar familiarizado con Asterisk, la forma en que trabaja su dial plan y también conocimiento en el lenguaje de programación Java. 

Con algunas modificaciones, luego podrían hacer alguna de las siguientes cosas:
  • Agendar un cron job que ejecute el programa en algún momento del día, por ejemplo, como llamada de  despertador.
  • Hacer una difusión masiva de un mensaje de audio, hacia una lista de números.
  • Realizar una campaña de marketing, donde se realicen llamadas y se haga preguntas de opción múltiple que se puedan responder marcando un digito.
  • Leer una lista de números desde una base de datos, etc.
Éstas son sólo algunas ideas, pero hay muchas posibilidades.

Los call files de Asterisk
Son archivos que, básicamente, contienen las instrucciones para realizar una llamada. Colocados en el directorio correcto, son detectados por Asterisk y éste ejecuta las instrucciones escritas en el archivo.

Estrategia para abordar el problema
Nuestra estrategia será escribir una aplicación Java que produzca estos archivos en un directorio temporal y luego los copie al directorio /var/spool/asterisk/outgoing/, de forma que Asterisk los pueda procesar. 

Es en realidad algo muy sencillo que luego podemos ir armando con mayor grado de complejidad y opciones según nuestra necesidad.

Sintaxis de un call file para reproducir un mensaje (o ejecutar una aplicación)
Tomado de http://www.voip-info.org, tan sólo lo traduje al español:
Especificar cómo y dónde llamar:
  • Channel: <canal>: Canal a utilizar para la llamada.
  • CallerID: "nombre" <número> Identificador de quien llama, Por favor notar: Puede no funcionar si no se respeta el formato: CallerID: "Un nombre" <1234>
  • MaxRetries: <número> Número de reintentos antes que la llamada falle (sin incluir el intento inicial, por ejemplo 0 es igual a un intento en total de realizar la llamada). El valor por defecto es 0.
  • RetryTime: <número> Segundos entre los reintentos, No insistir tan seguido sobre un teléfono que no está disponible. El valor por defecto es 300 (5 min).
  • WaitTime: <número> Segundos para esperar que la llamada sea contestada. El valor por defecto es 45.
  • Account: Poner el valor de cuenta a utilizar.
Si la llamada es contestada, conectarla aquí:
  • Context: <nombre del contexto> Un contexto en el archivo extensions.conf
  • Extension: <extensión> Una extensión definida en el archivo extensions.conf
  • Priority: <prioridad> La prioridad de la extensión desde donde se iniciará la conexión.
  • Set: Poner una variable para utilizar el la lógica del contexto (eejmplo: file1=/tmp/to ); en Asterisk 1.0.x usamos 'SetVar' en lugar de 'Set'
  • Application: Aplicación de Asterisk a ser ejecutada (se utiliza en lugar de especificar context, extension y priority)
  • Data: Las opciones a ser pasadas a la aplicación.
Nuevo (?) en Asterisk 1.4
  • Set: Puede ahora también escribir a funciones del dialplan como CDR()
  • AlwaysDelete: Yes/No -Si la fecha y tiempo de modificación del archivo es el futuro, el archivo de llamada no será borrado.
  • Archive: Yes/No - Mover hacia el subdirectorio "outgoing_done" con "Status: value", donde value puede ser Completed, Expired o Failed.
 Entonces, tenemos dos opciones, referenciar un contexto/extensión/prioridad que exista en nuestro archivo extensions.conf, o podemos invocar una Aplicación de Asterisk indicando sus parámetros.

Prerequisitos para probar el Demo.
  • Una instalación Ubuntu o CentOS donde se esté ejecutando Asterisk.
  • Si deseamos realizar llamadas hacia la PSTN, debemos tener configurada una troncal que nos permita hacer esto.
  • Un archivo de audio en el directorio /var/lib/asterisk/sounds/ llamado mensaje.gsm con algún mensaje de prueba que se reproducirá para las personas que contesten nuestras llamadas.
  •  Tener JDK instalado (se puede si está instalado con el comando java -version, caso contrario instalar).
  • Creamos el directorio /var/spool/asterisk/tmp/
  • Disponer de credenciales con privilegios en la instalación Ubuntu.
Ahora, creamos un archivo, que llamaremos AutoDialerDemo.java.

Como mencioné anteriormente, debemos tener creado el directorio /var/spool/asterisk/tmp/y el usuario que ejecute la aplicación debe tener permiso de escritura sobre el mismo (debería ser super usuario para descomplicar la explicación).
    //Directorio donde se crearán inicialmente los archivos
    private static final String TMP_DIR_PATH = "/var/spool/asterisk/tmp";
Utilizaremos un archivo que llamaremos prueba.cfg, que debe encontrarse en el mismo directorio que nuestro archivo AutoDialerDemo.java.
      
    //Al ejecutar la aplicación, se debe pasar como parámetro el nombre del archivo de configuración (por ejemplo prueba.cfg)
    generarLlamadas(args[0]);



Un ejemplo del contenido de nuestro archivo prueba.cfg sería:

    app.proveedor=TuProveedor
     app.numero_0=1234UnNumeroComoLoEsperaTuProveedor
     app.numero_1=1234OtroNumeroComoLoEsperaTuProveedor    
     app.numero_2=1159393260807EnMiCaso
     ...
     app.numero_9=1234UltimoNumeroComoLoEsperaTuProveedor


Finalmente, creamos un archivo .call por cada número en la lista, y lo estructuramos con los datos especificados en el archivo prueba.cfg:

           //Asignamos el nombre del archivo
            file = new File(tmpDir, filename + ".call");

            writer = new BufferedWriter(new FileWriter(file));

            String text = "";
          
            //Especificamos el canal, en este caso, la llamada que realizaremos
            text = "Channel: SIP/" + proveedor + "/" + numero;
            writer.write(text);
            writer.newLine();
          
            System.out.println(text);
          
            //Además del intento inicial, realizaremos un reintento si la llamada no es conectada
            text = "MaxRetries: 1";
            writer.write(text);
            writer.newLine();

            //El reintento lo realizaremos 60 segundos después del intento inicial, de ser el caso
            text = "RetryTime: 60";
            writer.write(text);
            writer.newLine();

            //Esperaremos 30 segundos a que nuestra llamada sea contestada
            text = "WaitTime: 30";
            writer.write(text);
            writer.newLine();

            //Una vez contestada, reproduciremos un mensaje
            text = "Application: Playback";
            writer.write(text);
            writer.newLine();
          
            //El mensaje a reproducir será el audio en el archivo mensaje.gsm
            //Recuerda que este archivo debe estar en el directorio /var/lib/asterisk/sounds
          
            text = "Data: mensaje";
            writer.write(text);
            writer.newLine();

Copiamos el archivo generado desde el directorio /var/spool/asterisk/tmp hacia el directorio /var/spool/asterisk/outogoing. Lo hacemos de esta forma para que asterisk no intente procesar un archivo incompleto:

             //Damos permisos al usuario asterisk sobre nuestro archivo
             Runtime.getRuntime().exec("chown asterisk:asterisk /var/spool/asterisk/tmp/" + filename + ".call");
             //Movemos el archivo desde el directorio temporal hacia el directorio donde asterisk lo procesará
             Runtime.getRuntime().exec("mv /var/spool/asterisk/tmp/" + filename + ".call /var/spool/asterisk/outgoing/" + filename + ".call");

        

 Compilamos el archivo java ejecutando el siguiente comando en la terminal:
     $ javac AutoDialerDemo.java

Y obtenemos el archivo AutoDialerDemo.class. Luego, asumiendo que el archivo prueba.cfg se encuentra en el mismo directorio que AutoDialerDemo.class, y que la información en él es correcta, ejecutamos:
     $ java AutoDialerDemo prueba.cfg

Aconsejo tener otra ventana de terminal abierta conectada al CLI de Asterisk, de forma que podamos ver qué sucede tanto en la salida de nuestra aplicación como en los mensajes de Asterisk.

Incluyo el archivo AutoDialerDemo.java.
¡Suerte con estas llamadas autogeneradas! Sólo intenta no hacer tus pruebas en el horario en que otros descansan zzz.