Advanced Asterisk. Days 4 y 5

Ya entrando en la recta final, continuamos con el tema de ayer de conexiones de tarjeteria y PSTN.

Primero van los conceptos teoricos sobre los tipos de sistemas digitales de telefonia Americanos (T1), Europeos (E1), las señalizaciones, los canales, servicios implementados como RDSI (ISDN), codificacion de las señales… realmente son temas que para un caso en concreto de uso hay que tenerlos claros.

Un ejemplo practico seria la interconexion duplex entre una centralita Asterisk y una Alcatel con tarjeteria en ambos lados. Para la comunicación de mensajes a nivel de servicios digitales, se implementa un protocolo de señalización llamado Q.931, pero mas concretamente de un protocolo variante especifico para esta funcionalidad de interconexión de centralitas, llamado Q.SIG.

Ahora vamos a la parte practica de configuracion, hay que considerar que existen dos tipos de configuraciones, la especifica para Estados Unidos y otra para Europa, en este caso voy a intentar de ir planteando las dos, porque cara a Digium la que se utiliza es la EEUU, pero para nuestros casos practicos seguramente sea la Europea.

Configuracion del /etc/dahdi/system.conf

Primero tenemos que configurar cada uno de los puertos

span = <numero_del_puerto>,<fuente_de_sincronizacion>,<line_built_out>,

Ejemplo americano:

span = 1,1,0,esf,b8zs

Ejemplo europeo:

span = 1,1,0,ccs,hdb3,crc4
– El 1 primero, es el numero del canal

– El 1 es para ser receptor de la fuente, y el 0 para ser el emisor
– El siguiente 0, es para no amplificar la señal si los cables son normales, o 1 si son demasiado largos (el cable que nos llega del operador esta en una ubicación muy apartada de donde esta nuestro equipo)
– ESF/CCS, las señalizaciones, americana y europea respectivamente
– B8ZS, y HDB3 son las codificaciones
– Finalmente CRC4, el sistema de control de errores

Luego se configuran, los bchan (canales de datos) y el dchan (canal de señalizacion)

bchan = 1-23
dchan = 24

– En modo americano

bchan = 1-15,17-31

dchan = 16

– En modo europeo

Y luego el loadzone = es/us y defaultzone=es/us es especialmente importante cuando se tratan de tarjetas digitales.

En el fichero /etc/dahdi/modules, hay que levantar el modulo especifico de la tarjeta de T1/E1 llamado wcte12x (primario con 1 puerto T1/E1 o wct4xxp (2 o 4 puertos T1/E1), y si hablamos de puertos BRI seria el modulo wcb4xxp

Finalmente se configura el chan_dahdi.conf muy parecido a las tarjetas analogicas Podemos empezar a amplicar elsistema de “contextos” para este fichero de configuracion.

[channels]

[Primarios]
callerid=asreceived
contexto=llamadas_entrantes
signaling= //Aqui va la configuracion especifica de los primarios, hay opciones como pri_cpe (si recibimos de un operador) o pri_net (si somos los emisores de la señal)
switchtype = //Otro especifico, teoricamente existen multiples tipos de primarios, la red National, la red de AT&T en estados unidos, o la unificada de Europa EuroISDN, los valores posibles, “national”, “euroisdn”, etc. Y en el caso que estemos interconectando dos centralitas, por ejemplo a la Alcatel que hablabamos antes, pues aquí se pone “qsig”
dahdichan=1-23 //los canales de datos que antes configuramos en el system.conf, caso Americano
dahdichan=1-15,17-31 //los canales caso Europeo
group = 1 //esto es practico para no tener que estar definiendo un canal en el extensions.conf para cada canal, se utiliza un “generico” que se aplica al “grupo de canales”, y se define como gX (siendo X el numero del grupo). Para este ejemplo una opcion seria: DAHDI/g1

Ademas un tema importante de los grupos es que se pueden configurar los mecanismos de selección de canal dentro del grupo. Se pueden aplicar distintas tecnicas de selección, como la secuencial empezando por el canal primero, por el final, metodo round-robin, etc. Esto se configura, al configurar el tipo de grupo en el extensions.conf. Antes puse DAHDI/g1, pero podria ser G1, r1 y R1 (la r es el metodo Round Robin)

Una gran diferencia con respecto a las lineas analogicas, es que las llamadas no entran a la extension start del dialplan, sino entran al telefono (DID) al que es llamado por tanto en el dialplan la extension “entrante” se define con el numero del DID

Ejemplos:

exten => 919191919,1,Dial(SIP/mitelefono)

exten => 929292929,1,Dial(SIP/tutelefono)

Pero esto ya lo vimos cuando trabajabamos con el Gateway de puertos BRI, Epygi, que tenia un mecanismo muy similar aunque se configurara externamente.

– Fax en Asterisk

A raiz de la version 1.8 mejoro bastante el soporte “nativo” para FAX con respecto a las versiones anteriores, tanto a nivel Passthrough por el protocolo T.38, como utilizando la maquina Asterisk como gestora de FAX. Pero realmente para esto segundo, el soporte de FAX por Asterisk es limitado o de pago si queremos utilizarlo en produccion. Aquí hay una explicacion detallada del tema

En nuestro caso ya explicamos como tener un sistema completo y libre utilizando Hylafax con el IAXModem bastante efectivo. A raiz del mensaje de Enesoluciones (ahora Fundacion Guadalux) pense que el sistema nuevo de Asterisk sustituiria el Hylafax brutalmente, pero parece que no va a ser asi de momento,por el tema este de las licencias de pago que hablaba (aunque al parecer Digium ofrece una unica licencia gratuita para solo 1 llamada concurrente, que seguramente en muchas instalaciones para PYMES sea suficiente).

– Asterisk Database (AstDB)

Asterisk implementa un sistema de bases de datos muy sencillo para almacenar informacion relativamente poco compleja. Es mas comodo que tener que andar trabajando con conectores ODBC y demas historias siempre y cuando busquemos aplicaciones concretas donde haga falta almacenar valores y acceder a ellos facilmente, pero especificamente del propio sistema de configuracion de Asterisk (ejemplo las Listas Negras de llamantes, familia blacklist)

Las funciones de lectura y escritura son extremadamente sencillas (totalmente integradas en el sistema Asterisk). Basicamente son usos de la aplicación Set y manejo de variables pero con la funcion DB() cubriendo esta nueva “variable”.

La variable esta compuesta por familia/clave/valor por ejemplo users/mitelefono/SIP/mitelefono

En este caso la clave mitelefono dentro de la familia, users, tendra el valor SIP/mitelefono (que por ejemplo es el canal SIP que utiliza nuestro telefono SIP).

Ejemplos:

Asignar a un registro de la base de datos: Set(DB(users/mitelefono)=’SIP/mitelefono’)

Consultar el registro: ${DB(users/mitelefono)}

Con todo esto parece que podemos “recortar” en variables globales dentro de los ficheros de configuracion basicamente. A lo mejor seria interesante montar algo serio que utilice esto a mayor escala como lo que comentaba esto de los Blacklist, aunque realmente tampoco tendra mucho misterio, algunas lineas. Me lo apunto como futura practica.

– Ultimo dia. 5: Seguridad en Asterisk

Para finalizar, y dar cierre al Asteirsk Advanced, el ultimo dia se trataron multiples temas relacionados con la seguridad en Asterisk

Sobre este tema tengo que hacer un comentario: justamente, ahora que estoy bastante desconectado del mundo “tecnologico” a nivel profesional, no tengo tanto acceso como antes a tarjeterias, equipos de trabajo y demas historias que me hacian el mundo facil en el progreso Asterisk.  Pero concretamente acerca de la seguridad en Asterisk, supuestamente el sistema mas “peligroso” en el que montar un Asterisk es abierto a Internet. Por ello en las proximas entradas, voy a estar focalizando en esta idea, ya que mi forma de “progresar” de ahora en adelante va a ser montando una maquina Asterisk en Casa y ofreciendo servicios concretos a individuales, a mi empresa (de forma altruista) y a otras empresa que quiza pudieran interesarme por el potencial (¿patrocinio o algo asi?) que pudieran ofrecerme (especialmente por los recursos economicos que pudieran aportar al tema).

El tema de seguridad en Asterisk tomaba dos perspectivas: el tipo de securizacion que habia que tomar en consideracion por niveles de “inseguridad” (desde el montaje de una maquina aislada de la red, hasta el montaje de una maquina publicado a internet), y por otro lado, todos la securizacion de todos los componentes del sistema (desde los accesos a la propia maquina hardware, pasando por el sistema operativo, hasta el mismo dialplan).

– Conclusiones y Consideraciones Finales sobre el Curso

Como comentaba el segundo dia debo determinar y concluir que el curso ha satisfecho mis expectativas, ya que realmente el interes de hacer un curso de este calibre, no ha suele ser tanto, la cantidad de informacion recibida, sino la posibilidad de “expandir” conceptos acerca de la especialidad en concreto que viene a tratarse, a traves de los profesores y los compañeros. Hay que considerar que el precio realmente no cubre solo las horas de enseñanza, sino tambien las horas de “relacion”. Es cierto que para “conectar” con otros individuales especialistas o no especialistas en un sector, no es realmente necesario hacer un curso, y que para el aprendizaje por ese precio se podrian llegar a conseguir incluso, horas de enseñanza particulares por internet pactando con algun profesional un precio por hora (algun dCAP) sin excesiva dificultad. Pero mas alla de estas dos posibilidades, y la primera en particular, tambien hay que considerar que el perfil de alumno que va a un curso de este tipo, no suele ser de “Lurker” ya que al costar (bastante) dinero, suelen ser o aportes profesionales (empresas que quieren formar a sus trabajadores especialistas), o aportes personales (autonomos o como yo esta vez, especialmente interesados en el sector).

Proxima parada: Examen dCAP. No se donde sera, pero desde hoy ya toca empezar a practicar y estudiar como el que mas. Segun parece, por los alumnos que se presentaron, el nivel del examen practico ha aumentado a practicamente al doble de dificultad que las ultimas convocatorias, y sobre el teorico no pude enterarme, ya que tuvimos que irnos a comer porque el examen se alargaba demasiado.

Asterisk Advanced. Day 3

Hoy voy a hacer una prueba, escribir un articulo durante la clase a modo “Inline”. Seguramente salga un articulo demasiado extenso pero al menos, lo máximo completo.

– Teoría de Macros en el DialPlan

En primer lugar un tema que no hemos visto hasta la fecha y es crucial para configuraciones de dialplan repetitivas, las Macros.

Dos conceptos basicos

Las macros se componen del contexto del Macro [macro-<nombredelmacro>]

Solo tienen una extension, la “s”
exten => s,1,Answer()
same => n,Hangup

Por otro lado, las Macros se ejecutan desde el Plan de Marcacion, como una aplicación cualquiera con el formato Macro(<nombredelmacro>, <argumento1>, <argumento2>, etc)

Luego dentro del contexto Macro para poder utilizar esos argumentos llamados se utilizan las variables especificas de las macros ${ARG1}, ${ARG2}, etc

Ejemplo:

[extensiones]
exten => 100,1,Macro(prueba,SIP/mitelefono, 30)

[macro-prueba]
exten => s,1,Dial(${ARG1},${ARG2})

Aparte disponemos de variables especificas de las Macro. ${MACRO_CONTEXT}, ${MACRO_EXTEN} y ${MACRO_PRIORITY}. Sirven para saber dentro de la macro, que contexto, que extensión y que prioridad llamó a la Macro.

Un ejemplo, si utilizamos un Buzon de Voz, que coincide con el numero de extension pues podriamos utilizar ${MACRO_EXTEN}:

[extensiones]
exten => 100,1,Macro(prueba,SIP/mitelefono, 30)

[macro-prueba]
exten => s,1,Dial(${ARG1},${ARG2})
exten => n,VoiceMail(${MACRO_EXTEN})

A partir de aquí ya podemos dar “rienda suelta” a la imaginacion y poder simplificar nuestro trabajo de escritura de tareas repetitivas.

– Asterisk Realtime

Ya conocemos esto de artículos anteriores, como el uso del Web-MeetMe (configuraciones de salas de conferencia directamente desde la Web, a través de bases de datos en “tiempo real” (realtime).

Pero ahora una visión un poco mas práctica de como se trabaja con Realtime, ya que realmente el Web-Meetme siguiendo los pasos venia prácticamente preparado paso por paso y no podíamos entender que estaba haciendo realmente a nivel interno.

La utilidad de Realtime sobre configuraciones en ficheros de texto, es simplemente el hecho de poder introducir modificaciones constantes de una forma ultra-rapida (mediante un interfaz web por ejemplo que acceda a la base de datos).

Un ejemplo tipico: en la web vemos el listado de usuarios, con un boton para borrarlos cuando los damos de baja, y luego un mini formulario en el que ponemos el usuario y la contraseña y damos de alta una extensión inmediatamente. No habria que estar accediendo al servidor, accediendo al fichero de texto, editándolo, guardando, recargando el modulo, etc…

En configuraciones estáticas (situaciones en las que rara vez se cambia una extension por ejemplo), es poco practico por que puede salir mas caro el collar que el perro. Pero si un dia nos da por diseñar una interfaz web sencilla, y una base de datos (fichero .sql) que precargue nuestros valores default, podriamos implementar esto en tiempo record y podríamos tenerlo siempre presente en todas nuestras instalaciones (quizá algún día lo plantee esto como un articulo, muchos temas ya tengo pendientes conforme avanzamos en el mundo de Asterisk).

Un primer inconveniente que encontramos, es que Asterisk pretende centralizar todas las conexiones a bases de datos a traves de una capa de abstraccion como ODBC, es decir que los conectores directos nativos como MySQL y PostgreSQL tienden a su desaparicion. Para los no demasiado experimentados en el mundo ODBC esto podria ser un inconveniente a corto plazo.

Si recuerdan, el Web-Meetme lo hacia todo a traves de ODBC asi que este problema lo salvan (lo que no salvan que Meetme tiende a desaparcer tambien en favor de ConfBridge (nueva aplicación para conferencias sin necesidad de timing, tambien hablaremos de ella en un futuro).

Ahora sobre la configuración los ficheros involucrados

En primer lugar /etc/asterisk/extconfig.conf necesitamos añadir una linea del tipo
<nombredelaconfiguracion> => <driver>,<nombrebasededatos>,<nombretabla>

En el caso ejemplo del Web-Meetme era:
meetme => odbc,meetme, booking

El segundo fichero es el /etc/asterisk/res_config.conf

[nombrebasededatos]
enabled => yes // Esta activada la conexion
dsn => el Data Source Name del driver ODBC
pre-connect => yes // La conexión se ejecuta al arrancar Asterisk
username => usuario de la base de datos // En caso que conectemos por Puerto a la base de Datos, como en bases remotas
password => password de la base de datos // Lo mismo que lo anterior

En el ejemplo que estamos siguiendo:

[meetme]
dsn => meetme (este es el contexto que creamos antes en el sistema)
username => asterisk (supuestamente va a ser nuestro usuario para asuntos de Asterisk y servidor de base de datos)
password => asterisk (o la que le pusiéramos)
pre-connect => yes
enabled => yes

Ahora la configuracion del driver odbc en el sistema, /etc/odbc.ini

[meetme]
Description = ODBC para MySQL // Una descripcion cualquiera
Driver = MySQL // El driver ODBC que utilizamos, en este caso para MySQL por el tema ese que va a tender a desaparecer que comentábamos antes
Server = localhost // Servidor donde esta la base de datos
Database = meetme // Nombre de la base de datos con la que trabajaremos
Port = 3306 // Puerto de la base de datos
User = asterisk // En caso que conectemos por puerto en vez de por Socket
Password = asterisk // En caso que conectemos por Socket
Socket = /var/run/mysqld/mysqld.sock // Por aquí conectamos por Socket

Y finalmente /etc/odbcinst.ini

[MySQL]
Description = MySQL ODBC MyODBC Driver
Driver = /usr/lib/odbc/libmyodbc.so // librería ODBC del Driver MySQL
Setup = /usr/lib/odbc/libodbcmyS.so // librería ODBC de Configuración MySQL

Solo quedaria configurar la tabla y base de datos y ya preparado.

Algunas consideraciones adicionales: para reducir el numero de peticiones a cache, el fichero de configuracion del modulo que estamos convirtiendo en “RealTime” introducimos la siguiente variable: rtcachefriends=yes

De aquí pueden surgir multiples ideas prácticas que me gustaria probar personalmente y dedicar un articulo especifico con mis resultados, como por ejemplo, crear una funcion en func_odbc.conf para consultar algo especifico de una base de datos externa para tratarlo a traves del DialPlan, como por ejemplo consultar el telefono de un Cliente.

– CDR y CEL

Esta parte trata sobre como se gestiona CDR (Registro de Detalles de Llamada) y la nueva implementación mas detallada del registro CEL, en el que es posible ver a nivel de flujo de llamada de DialPlan, no solo a nivel de canal. La verdad es que es meramente informativa con informacion sobre los campos que se utilizan, y algunas aplicaciones de dialplan para edicion, pero realmente merece un articulo bastante amplio para poder entrar en detalle incluso algun mecanismo para extraer informacion como vimos en el articulo de CDR-Stats, una gran aplicación para poder visualizar los datos de forma bastante generica (y recuerdo que quede en montar un software para analizar llamadas pero mas en detalle para un proposito en concreto).

– El mundo de las Tarjetas Analogicas

Ya dedique varios articulos a este tema cuando empece a trabajar con la tarjeta TDM410P como el siguiente y la segunda parte del mismo.

Algunos conceptos novedosos y no vistos hasta la fecha:

Sobre la tecnologia Analogica, existen tres posibles de sistemas de señalizacion, (en el fichero chan_dahdi.conf) ground start (en desuso), loop start (tambien en desuso) y kewl start (sistema mas utilizado en la actualidad, 99% de los casos).

Otra novedad que trae la version 1.8 es la posibilidad de crear contextos en el chan_dahdi.conf y tener por ejemplo un contexto generico [channels] donde especificar ciertos argumentos especificos de la tecnologia analogica (que eran los que soliamos definir antes del channel => cuando utilizabamos un modulo FXO

Ejemplo:

[channnels]
usecallerid = yes
transfer = yes

[telefono-analogico]
callerid = “Telefono Analogico” <1001>
context= extensiones
signaling = fxo_ks
dahdichan = <el_canal_que_definimos_en_/etc/dahdi/system.conf>

[linea-analogica]
callerid=asreceived
context = llamadas_entrantes
signaling = fks_ks
dahdichan = <el_canal_que_definimos_en_/etc/dahdi/system.conf>

Pero luego, en el Dialplan tenemos que seguir definiendo en canal a la vieja usanza (DAHDI/1, DAHDI/2, etc…)

Dato importante de las lineas extrantes analogicas, es que hay que mandarlas a un contexto en el DialPlan (por ejemplo, llamadas_entrantes) y dentro de ese contexto, poner la extension “s” (start) ya que es imposible reconocer hacia donde pretende ir esa llamada por las limitaciones de la “analogia”.

Mañana parece que seguiremos con el tema de las conexiones de Tarjeteria, pero esta vez con una nueva que no hemos visto hasta la fecha, una tarjeta de Primarios.

Espero vuestros comentarios sobre como quedo esta “modalidad” de blogging inline. Para mi particularmente resulto mas comoda porque en los huecos libres podia ir escribiendo, y no tener que hacer todo el texto ya a deshoras y ademas tambien ha servido un poco con “apuntes personales” de lo visto para revisiones futuras (como realmente es el blog entero para mi personalmente).

Asterisk Advanced. Day 2

Pasado el primer dia “introductorio” se empiezan a ver conceptos y aplicaciones mas interesantes para nuestro sistema Asterisk. Una de las conclusiones que he sacado en favor del curso, algo que personalmente me suele costar bastante sacar de la mayoria de los cursos que he ido, es que la verdadera utilidad del curso no reside en el material que puedes encontrar en cualquier pagina medianamente buena que trate sobre asterisk como www.voip-info.org, sino realmente en la cantidad de aplicaciones practicas que surgen a raiz de la experiencia del profesor, y tambien de los compañeros del curso.

Realmente Asterisk, exceptuando la idea basica de una centralita, o del concepto generico de “quiero montar un callcenter” o “quiero montar una centralita para mi empresa”, sin ideas practicas de calidad, es totalmente inutil. Pero es cuando las ideas empiezan a ebuillar cuando se pueden empezar a pensar en infinidad de aplicaciones para la vida diaria que pueden resultar extremadamente utiles.

Por eso mas que escribir sobre teoria que se ha visto, y puede consultarse como dije, en VoipInfo, voy a comentar algunas que fueron surgiendo:

– Sistemas de Monitorizacion de llamadas

Seguramente todo buen conocedor de Asterisk (que no es mi caso) sepa, que existen aplicaciones para la grabacion de llamadas. Pero ya que el canal de llamadas puede ser “escuchado” para ser grabado en un fichero de audio, tambien podria ser “escuchado” en tiempo Real. Ahi es donde entran las aplicaciones “Espias” como ExtenSpy y ChanSpy. Dos aplicaciones muy faciles de utilizar en un dialplan:

exten => 100,1,Answer()
exten => 100,n,ChanSpy()
exten => 100,n,Hangup ()

Y simplemente accediendo a la extension 100, tenemos “barra libre” para escuchar todos las conversaciones en el canal SIP de nuestra maquina Asterisk pasando de una a otra desde el telefono a traves del boton “*”

– Generacion de llamadas Automaticas

Por otro lado, algo tambien muy interesante, es la posibilidad de generar llamadas automaticas a traves de un fichero de “llamada” que se introduce en un directorio que esta siendo constantemente “monitorizado” por un demonio de Asterisk que lo ejecuta, y procesa los comandos de la llamada.

Esto por ejemplo puede ser util, a traves de un script autoejecutado en el arranque del sistema, cuyo procedimiento sea, si por ejemplo se cae un servicio critico del servidor, y tenemos instalado un minimo asterisk en ese servidor al que hemos conectado una extension SIP nuestra para alertas, hacemos que cree un fichero de llamada a medida y lo movemos al directorio que comentaba antes ( el directorio exacto es /var/spool/asterisk/outgoing). En este caso, lo que haria seria generar la llamada a nuestra extension alertandonos que el servicio se cayo. Muy practico porque eventualmente todos sabemos que el telefono suele ser de prioridad nivel maxima mientras que el correo electronico (como aplicaciones tipo Nagios que generan y envian correos de alerta), suele ser de prioridad media o medio baja dependiendo el caso. O perfectamente podriamos combinar sistemas como Nagios y Asterisk para diseñar un sistema de alertas mediante mensajes de voz a un telefono provenientes del servidor.

El formato de estos ficheros de llamada es muy sencillo. Un fichero de texto con los posibles siguientes comandos:

Channel: SIP/mi_telefono //El canal a traves del que se cursara la llamada
Application: Playback //Queremos que ejecute la aplicacion Playback para reproducir un mensaje automatico a voluntad
Data: windows-server-caido //El fichero de audio que vamos a lanzar con la aplicacion Playback, en este caso tiene que encontrarse en el correspondiente directorio de sonidos de Asterisk en un formato permitido para su reproduccion por ejemplo windows-server-caido.wav
Codecs: g729, ulaw, gsm // Codecs permitidos por el canal
MaxRetries: 3 // Numero de intentos que se tratara de realizar la accion con exito

– Edicion y personalizacion del Features.conf

Por otro lado, tambien hoy se vio el fichero de configuracion, features.conf, en el que basicamente se definen la utilidad de las pulsaciones de botones DMTF y como seran interpretados por las aplicaciones que conllevan especialmente servicios de llamada como Dial y Queues.

Basicamente ya es sabido que existen en ese fichero una serie de definicios por defecto para realizar “Features” (Caracteristicas) como la transferencia de llamadas, el Parking de llamadas, etc, que quiza comente mas en detalle en un futuro.

Pero siguiendo con la linea practica, un ejemplo que se probo en la clase, fue la posibilidad de crear “Features” a medida, como por ejemplo, mapear dos combinaciones de teclas para subir y bajar el Pitch del canal de audio (para los entendidos en efectos de sonido, es la escala de frecuencia). Esto quiere decir que por ejemplo si tenemos a un operador en la oficina que tiene una voz muy aguda, y queremos dotarle de una voz mas grave sin tener que prescindir de esta persona para llamadas determinadas, le podemos configurar en su telefono la posibilidad de bajar 4 o 5 puntos el nivel de frecuencia, y sonaria tal y como deseamos para el receptor de la llamada. Asunto resuelto, ya tenemos un locutor de radio instantaneo a coste 0.

¿Como se consigue este efecto?

Primero en features.conf bajo el contexto [applicationmap] definimos algo asi:

pitchUp => #1,self/both,Set(PITCH_SHIFT(both)=high)
pitchDown => #2,self/both,Set(PITCH_SHIFT(both)=low)

Con esto decimos que para conseguir alcanzar la caracteristicas “pitchUp” pulsando almohadilla + 1 subimos la frecuencia (tonalidades agudas) y al pulsar # + 2 bajamos la frecuencia (tonalidades graves)

Ahora para que esto sea aplicable a una aplicacion de llamada, es necesario modificar una variable general de Asterisk llamada __DYNAMIC_FEATURES (atencion a las dos _ del comienzo de la variable).

exten => 100,1,Set(__DYNAMIC_FEATURES=pitchUp#pitchDown)
exten => 100,n,Dial(SIP/mitelefono)
exten => 100,n,Hangup()

Ahora al llamar a la extension 100 y contactar con ese canal ahi definido, ambos interlocutores de la conversacion podran manipular su voz pulsando las combinaciones de teclas anteriormente descritas. Todo un lujo de goce y disfrute para la conversacion.

– Importante Novedad de la version 1.8 de Asterisk

Finalmente para terminar, aun a sabiendas que me quedan mil cosas en el tintero que podria escribir, quiero comentar algo nuevo que ha surgido en las ultimas versiones de Asterisk y SIMPLIFICA los Dialplans una burrada.

Hablo de “SAME”. Esto simplamente permite el hecho de poder obviar el exten => junto al numero de extension que vamos repitiendo en un flujo de llamada para una extension concreta

Antes:

exten => _6XX32XZ1X,1,NoOp()
exten =>  _6XX32XZ1X,n,Dial(${Troncal}/${EXTEN})
exten => _6XX32XZ1X,n,Hangup

Ahora:

exten => _6XX32XZ1X,1,NoOp()
same => n,Dial(${Troncal}/${EXTEN})
same => n,Hangup

Definitivamente MUY comodo. Gracias al iluminado por implementar esta mejora.

Eso es todo por hoy, mañana espero, mucho mas.

MeetMe in a Box: Web-MeetMe: Conferencias de Audio de altos vuelos.

Hoy en día es muy común ver multitud de software web, capaz de ofrecer funcionalidades de conferencias online, webminars (seminarios web), y videoconferencias llevadas a reuniones. Llegaremos a eso algún día, pero como para ello se requiere el software, y el hardware especifico (y de calidad), y en estos momentos como todos sabemos, el horno no está para bollos (pese a que la gran mayoría sabemos a día de hoy lo que nos podríamos ahorrar, existen aún defensores, como George Clooney en “Up in the Air” que defienden “lo presencial”).

De momento no vamos a conformarnos con poco, y vamos a tratar de montar un sistemas de conferencias por Audio, de bajo coste, y si puede ser con Teléfonos de por medio, que hoy en día, las llamadas a fijos están muy baratas y dan una calidad de audio ““streaming”” excepcional.

Y a este sistema, Asterisk lo llamó MeetMe. Y realmente es tan simple como el tema de los buzones de voz (incluso más simple aun!) con su Aplicación con el mismo nombre, y su fichero de configuración meetme.conf. Pero voy a dar un paso más allá: Haciendo uso de esta base, poder obtener el potencial de un sistema de Gestión de Conferencias de Audio en tiempo real, a través de una Interfaz Web. Esto, realmente suena mucho mejor que “una conferencia a tres (o a cuatro)”, como quien dice. Vamos allá.

Para la Interfaz Web MeetMe van a hacer falta algunos elementos. Algunos ya los tendremos si hicimos la instalación de LAMP en su día.

En primera instancia vamos a ir descargando el paquete estrella, la interfaz Web-MeetMe. La página oficial seria: https://sourceforge.net/projects/web-meetme/

# tar –xvf web-meetme_(versión que sea)
# cd web-meetme

En primer lugar toca configurar el Driver ODBC para conectar con nuestra base de datos MySQL. Hay que instalar algunos detalles para el ODBC de nuestro sistema
# aptitude install unix-odbc
# aptitude install libmyodbc

Ahora configuramos el driver en condiciones. Primero editamos /etc/odbcinst.ini para crear un driver a MySQL:

[MySQL]
Description = MySQL ODBC MyODBC Driver
Driver = /usr/lib/odbc/libmyodbc.so
Setup = /usr/lib/odbc/libodbcmyS.so

Luego configuramos el fichero /etc/odbc.ini con la siguiente información.

[meetme]
Description = ODBC para MySQL
Driver = MySQL
Server = localhost (local, o servidor donde tengamos la base de datos con el driver ODBC)
Database = meetme (tenemos que crear una base de datos igual que la de Asterisk, pero con este nombre, para diferenciar un poco, en mysql,
Port = 3306
User            = asterisk
Password        = asterisk
Socket = /var/run/mysqld/mysqld.sock (puede que este fichero de socket este en otro sitio dependiendo la distribución donde tenemos nuestro sistema)
Stmt =
Trace = yes
TraceFile = /tmp/odbc.log

No entro en detalles, porque esto es configuración del conector ODBC para acceder a nuestra base de datos MySQL que supuestamente, ya tenemos instalada.

Para configurar la nueva base de datos meetme, simplemente podemos entrar en la consola mysql #mysql –u asterisk –p y poner el comando: CREATE DATABASE `meetme` ;

A partir de ahí generamos las tablas. Si no hemos salido del directorio web-meetme del paquete que descargamos antes ejecutamos:
# mysql –u asterisk –p < ./cbmysql/db-table-create-(version-que-sea).txt
# mysql –u asterisk –p < ./cbmysql/upgrade-db.txt

Ahora realizamos la configuración del conector ODBC de Asterisk, el fichero de configuración es /etc/asterisk/res_odbc.conf, creando un contexto específico para meetme.

[meetme]
dsn => meetme (este es el contexto que creamos antes en el sistema)
username => asterisk (supuestamente va a ser nuestro usuario para asuntos de Asterisk y servidor de base de datos)
password => asterisk (o la que le pusiéramos)
pre-connect => yes

Ahora en extconfig.conf (si tenemos el fichero de ejemplo, tan solo buscamos la línea meetme => y cambiamos lo que haya al completo por:
meetme => odbc,meetme,booking

Como todo lo hacemos a través del driver ODBC pues los Call Detail Records, los vamos a registrar de esta manera también. En el fichero cdr_adaptative_odbc.conf:

[wmm]
connection=meetme
// este es el context que utilizamos antes en res_odbc.conf)
table=cdr
// vamos a llamar a la tabla igual que la llamamos en la bbdd Asterisk. Realmente podríamos basarnos en la misma base de datos que ya tenemos, pero en este caso, para que no sea estrictamente necesario seguir el planteamiento de CDR-Stats vamos a independizarlo.

También hace falta introducir una pequeña opción en meetme.conf para evitar usar una columna del Asterisk RealTime para meetme que web-meetme no utiliza:

logmembercount=no

Después de esto tenemos una opción para acceder al sistema utilizando un servicio LDAP, o utilizando usuarios creados a mano en la base de datos. En nuestro caso de momento, vamos con esta opción, ya que a priori tampoco deberíamos tener tantos… o sí. Me apunto esto para en un futuro, actualizar con un sistema LDAP como ampliación del poder de Asterisk + LINUX. Para crear la estructura de la tabla “user”, como antes en el directorio web-meetme ejecutamos:
# mysql –u asterisk –p < ./cbmysql/db-admin-user-create.txt

Con esto ya tenemos creada la base del sistema.

Ahora vamos a configurar el sistema Web-Meetme en si.

En primer lugar tenemos que preparar la interfaz web dentro de nuestro directorio raíz donde se publican las web de nuestro servidor Apache. Por regla general y por defecto suele ser /var/www. Ahí podemos crear un nuevo directorio específico para Web-Meetme
#mkdir /var/www/web-meetme

Ahora vamos a copiar todo el tarball que descargamos al principio de Web-Meetme en este directorio recién creado:

#cp –r /ruta/donde/este/nuestro/tarball/descomprimido /var/www/web-meetme

Ahora toca configurar los parámetros de nuestra Interfaz Web en los ficheros de configuración de la misma, en primer lugar dentro del directorio raíz de web-meetme vamos /lib/defines.php de momento lo básico es configurar los datos de acceso a nuestra base de datos y algunos campos clave:

define (“WEBROOT”, “http://ip-nuestro-servidor/web-meetme/”);
// La dirección web relativa de nuestro
define (“FSROOT”, “/var/www/web-meetme/”);
// La ruta a la interfaz
define (“LIBDIR”, FSROOT.”lib/”);
// Esto tal cual

Finalmente editamos una más, para identificación de usuarios, en nuestro caso habíamos creado una tabla “user” (automáticamente durante el proceso de carga de datos SQL que hicimos antes) dentro de nuestra base de datos meetme para la administración de usuarios:

define (“AUTH_TYPE”, “sqldb”); // adLDAP or sqldb

Existe un usuario en la base de datos administrador creado por defecto. Que luego usaremos para acceder el sistema y poder crear usuarios adicionales personalizados.
Usuario: wmm@localhost
Password: wmmpw

También es necesario configurar los parámetros de la base de datos. En este caso se realiza desde el fichero dentro de /lib/database.php:

$database = ‘meetme’;
$host = ‘localhost’;
$username = ‘asterisk’;
$password = ‘asterisk’;

Si os fijáis este fichero hace referencia a un módulo DB.php. Para poder hacer uso de este también es necesario instalar un paquete, php-pear y su módulo db
# aptitude install php-pear
# pear install db
El caso es que al parecer el modulo db ha quedado obsoleto y lo sustituye mdb2
# pear install mdb2 (aunque con el primero ya es suficiente en el momento que escribo este artículo)

Por otro lado nos toca configurar la interfaz para comunicarse con el Asterisk Manager. Para ello debemos configurar primero el manager de Asterisk y añadir un usuario para esto específico. En el directorio /etc/asterisk, fichero manager.conf, creamos un nuevo contexto, que va a ser justamente el usuario que vamos a utilizar:

[meetme]
secret = meetme (la password que queramos)
read = call
write = command,originate
Y luego como siempre #asterisk –rx ‘manager reload’

Y ahora en el directorio de la interfaz web de Web-Meetme, dentro de /phpagi tenemos un fichero de configuración de ejemplo que vamos a utilizar
#cd /var/www/web-meetme/phpagi
#cp phpagi.example.conf /etc/asterisk/phpagi.conf

Y lo editamos asi:
# vim /etc/asterisk/phpagi.conf

Dentro de [asmanager]
server=localhost
port=5038
username=meetme
secret=meetme

También tenemos que editar el fichero index.html para adaptarlo a la ruta relativa de nuestra web. Algo así:

<META HTTP-EQUIV=”REFRESH” CONTENT=”0; URL=http://servidor_ip/web-meetme/meetme_control.php”>

Y ya está todo lo básico. Ahora podemos acceder a nuestro sistema Web MeetMe desde
http://ip_servidor/web-meetme

Lo último de todo sería configurar una marcación en el extensions.conf para poder acceder a nuestro sistema, sea desde un DID que tuviéramos configurado, o directamente a la extensión en concreto. Por ejemplo:

exten => 5000,1,NoOp()
exten => 5000,n,Answer
exten => 5000,n,MeetMe()

Y con esto marcando el 5000 si en la interfaz habíamos creado un número de conferencia, nos pedirá, el número de conferencia y el PIN asignado para acceder a la misma.

Lo más curioso de esto es que en este proyecto también está presente Areski Belaid, creador del CDR-Stats y también de A2Billing, uno de  “tarificadores” más reconocidos en Asterisk, y desde este Blog agradecemos sus contribuciones al mundo de la Interfaz web para Asterisk.

Otras curiosidades que he encontrado, php-agi no está diseñado para trabajar con una version PHP superior a 5.2. Es por esto por lo que aparece un error en el log de apache constante:

PHP Parse error:  syntax error, unexpected T_GOTO, expecting T_STRING

La solución a este problema es muy fácil, la function goto está obsoleta, por eso vamos a nuestro directorio de web-meetme /var/www/web-meetme/phpagi y dentro modificamos el fichero phpagi.php, vamos a la línea donde aparece:

“function goto”

Y la cambiamos por “function goto2”. Así de simple.

Así el sistema quedaría configurado como para poder crear una sala de conferencias, visualizar los usuarios, expulsarlos a voluntad, bloquearles el micrófono, gestiones simples de administración de conferencias… aunque todavía no he llegado a alcanzar el 100% de la funcionalidad. La documentación es muy pobre, y mis vanos intentos de conseguir resultados no han llegado a buen puerto. Por ejemplo la función de Invite, para poder ser aplicada a través de un Troncal SIP, no consigo hacer que el sistema se autentifique correctamente para lanzar la llamada a través del mismo. La mayor parte de la configuración se consigue editando las variables del fichero defines.php, aun así, he de reconocer que el software tiene un nivel de personalización bastante grande, ya entrare en detalles sobre esto en otro momento. Al menos con esto es posible tener en marcha lo básico para poder trabajar eficientemente.

Conquistando el Dialplan II: Configuración DID para Operadores IP

Para todos aquellos que utilizamos operadores SIP tenemos la gran posibilidad de adquirir múltiples canales entrantes a muy bajo coste. A día de hoy la verdad que las llamadas salientes salen realmente caras, sobre todo si nos vemos en entornos empresariales. Ya hace tiempo os comente múltiples alternativas que había barajado en su día, con operadores como Netelip, Voztelecom, Telsome. A día de hoy, 2 céntimos el minuto para llamadas nacionales: Es muy caro. Tenemos alternativas internacionales como CheapVoip, pero aquí entra en juego el tema de las latencias. Además estas no nos ofrecen líneas de entrada y/o DID por tanto no podemos adquirir un sistema integral de llamadas tanto de entrada como de salida.

Aquellas empresas que si ofrecen canales de entrada, “se aprovechan” a un alto coste para la salida. Podemos combinar ambas soluciones, y de hecho, debemos, pero ya en estos casos las líneas de entrada empiezan a compensar cada vez menos.

Aun así, para configuraciones de pocas líneas de entrada (menos de 10) y relativamente pocos DID, (menos de 50), siguen siendo soluciones factibles. Por ejemplo una de las soluciones más óptimas en el mercado español, VozTelecom, con líneas de calidad muy muy alta a nivel de latencia, jitter, etc., ofrece por 8 euros, 2 canales de entrada, y 1 DID, 4 euros el DID adicional geográfico. Encima, los temas técnicos los libramos, y no tenemos que contratar mantenimientos adicionales para preservar la calidad del servicio

Si optamos la opción de Telefónica, tenemos una línea RDSI por 29 euros al mes, más el mantenimiento, habría que sumarle, mínimo, 4 euros para preservar una calidad aceptable de respuesta. Esto hace 33 euros. Luego los DID son relativamente baratos, en torno a los 2 euros.

Si no queremos optar por la opción del primario, 4 RDSI haciendo un grupo ISPBX (para saltos automáticos y demás), sumaria un total de 132 euros. En caso de VozTelecom hablaríamos de 32 euros. Luego si queremos 30 DID, serian 60 euros más para Telefónica 192 euros, y 120 euros para Voz Telecom: 152 euros. Solo 45 euros, estamos en el umbral. Aunque obviamente la solución con líneas RDSI es muy superior a la solución VOIP, porque además que podríamos “aislar” el sistema PBX a un nivel puramente local, si requerir de Internet, la calidad siempre suele ser superior a nivel de voz. Solo con un Gateway Epygi como el que vimos antes, tendríamos resuelta la papeleta.

Vamos a poner el caso concreto, de que elijamos la solución VoIP. Ahí vamos con la configuración:

En caso del Epygi, realmente no necesitamos un comando “register” en el fichero sip.conf para registrarnos contra el troncal. Pero en caso del operador SIP, si haría falta, como vimos con anterioridad. Esto nos “obliga” a ir hacia la extensión del Dialplan dentro del contexto que seleccionemos específicamente.

Y desde esa extensión, tendremos que realizar la configuración para seleccionar el DID que “recibamos” según los mensajes SIP que se intercambian durante la comunicación. Esto ocurre con la mayoría de los operadores IP, aunque algunos ejercen de troncal de forma equivalente al Epygi, que no necesitaremos realizar selección alguna:

En el extensions.conf imaginando que si pusimos contexto destino, en la configuración del operador SIP, pero no pusimos extensión destino en el comando Register (último parámetro /ddi como vimos antes):

exten => s,1,NoOp()
exten => s,n,Set(cNum=${SIP_HEADER(TO):5:9})
exten => s,n,GotoIf($[“${cNum}” = “987654321”]?1,1)
exten => s,n,GotoIf($[“${cNum}” = “912345678”]?2,1)
exten => s,n,GotoIf($[“${cNum}” = “988776655”]?3,1)
exten => s,n,Hangup()

Con la variable general SIP_HEADER, seleccionamos la cabecera del mensaje SIP, y nos vamos a la posición 5 longitud 9 (el número de teléfono) para guardarlo en una variable local que le llamamos cNum. Aquí en 99% de los casos se encuentra el DID. De todas formas haciendo debug en la consola (# asterisk –r) podemos ver exactamente qué valor está recibiendo esta variable, cNum

Esta sintaxis es nueva para nosotros. La aplicación GotoIf es condicional. Con el formato GotoIf($[condición], se cumple, no se cumple), En este caso concreto, si se cumple, saltamos al contexto 1, 2 o 3 según lo que se cumpla, y si no se cumple, pasamos a la siguiente prioridad.

La consulta de variables en Asterisk tiene el formato ${variable} en cambio la “escritura” de las mismas con la aplicación Set, se realiza sin nada, variable=. Esto es un poco técnico, aun con ciertos conocimientos de programación, esto se aprende en cuestión de segundos.

Así en vez de ir discriminando con extensiones con el número DID como hacíamos con el Epygi, lo haremos con este sistema por condicionales. Lo que no tengo muy claro todavía es porque algunos operadores mandan bien (y sin entender a qué me refiero con “mandar bien” el DID para asignarlo directamente como extensión), y para otros, hay que hacer operaciones como estas para salir al paso. Si lo averiguo, actualizare este mensaje.

Para finalizar con todo esto, voy a aprovechar, para hacer un apunte fuera del contexto. El tema es que Asterisk, por ventaja, o desgracia, favorece mucho a los informáticos, y acerca un mundo anteriormente exclusivo a ciertos técnicos especializados, o especialistas de las telecomunicaciones, al mundo de los informáticos. Por esto si realmente no tenemos nociones extensivas tanto de Linux como de programación, nos vamos a ver con un sistema bastante simple, (aun aceptable comparativamente con otras soluciones PBX), pero no vamos a poder sacar toda la potencia de su interior al máximo. No voy a pararme demasiado en temas de programación, variables, condicionales, bucles, aunque si explicando el formato, porque doy por supuesto que más o menos entendemos de que estoy hablando, y más considerando que desde hoy, la curva de aprendizaje va mejorando para el público entendido en esta materia, pero va a empeorar drásticamente para los que carezcan de estos conocimientos.

Conquistando el Dialplan I. Aplicaciones Asterisk: Voicemail

Como ya sabemos, el Dialplan, plan de marcación, es el esqueleto en esencia de Asterisk. A partir de este se abre el sin fin de posibilidades que nos ofrece este sistema.

Solo el que conoce lo que ofrece el Dialplan al 100%, es aquel que realmente conoce Asterisk de verdad. Por ello, las series de documentación sobre Dialplan serán mensajes mas cortitos pero no por ello menos interesantes  y que ayudaran a organizar mejor la información.

Realmente ya vimos parte del potencial del Dialplan, con la creación de una operadora automática de coste cero, ahora vamos a ver las funciones de Buzón de Voz para nuestras extensiones. Aquí básicamente hay dos actores principales. La Aplicación Voicemail, y el fichero voicemail.conf

El fichero voicemail.conf puede llegar a ser todo lo complejo que deseemos en función de nuestras necesidades, pero voy a comentar un caso práctico en el que podemos ver diversa funcionalidad que podemos llegar alcanzar. Como la mayoría de los ficheros de Asterisk, se divide en contextos, como casi siempre, general, suele ser el genérico que afecta a todos los contextos por igual.

[general]
format=wav
//Formato de las grabaciones para el buzon de voz. Se admiten otros formatos como gsm.
serveremail=direccion@queenvia.com
//Direccion del remitente de los envios
attach=yes
// Para enviar el fichero adjunto en los emails con el audio
delete=yes
// Para permitir la opción de borrado del mensaje de voz local en el servidor una vez enviado por correo eletronico
maxmsg=100
// Maximo numero de mensajes permitidos en la bandeja local por buzon
maxsecs=180
// Maximos segundos por mensaje
minsecs=2
// Minimos segundos por mensaje para desechar los mensajes vacios o casi vacios
skipms=3000
// Opciones del mensaje de audio, para indexarlo cara a desplazamientos X ms adelante o detrás cuando sea reproducido en el pc del destinatario
maxsilence=10

// Silencio máximo permitido, esto es importante cara a poder desconectar la llamada en caso de silencio antes de cumplir el máximo posible caso 180 segundos (en nuestro ejemplo)
silencethreshold=128
// Este es el umbral de audio para el que consideramos que es un silencio, de aquí podemos ir mas abajo o mas arriba en función de nuestra necesidad, no hay un valor “ideal”
maxlogins=3
// Intentos de acceso a voicemail, en caso de sobrepasarlos, Asterisk desconectara al usuario de su cuenta SIP/IAX
emailsubject=Nuevo Mensaje de ${VM_CALLERID}
emailbody=Buenos días ${VM_NAME},\n\nHemos recibido un mensaje en su buzon de voz…
// Esto seria el asunto y el cuerpo del mensaje email. Aquí se pueden aprovechar variables para poder formatear el correo y mostrar datos quizá interesantes para el destinatario. Algunas de estas variables de ejemplo:
${VM_CALLERID}: El numero identificador del llamante (el número de teléfono)
${VM_NAME}: El nombre del dueño del buzon (lo definiremos más adelante)
${VM_DUR}: Duracion del mensaje
${VM_DATE}: Fecha y hora de recogida del mensaje
Mas variables pueden encontrarse aquí: en su correspondiente sección (tampoco son muchas más)
emaildateformat=%A, %B %d, %Y at %r
// Formato de la fecha para el email. Para la variable VM_DATE. Consultar el manual de date para mas información (# man date)

Con esto tenemos más que suficiente para componer mensajes para el buzon de voz y enviarlos por email. Ahora vienen los contextos. Como siempre, si es [default] es el genérico, y luego los contextos específicos. En principio vamos a poner uno genérico y uno especifico.
[default]
1234 => 5678,Buzon de Ejemplo,ejemplo@buzones.com
– En primer lugar, el número del buzón, luego lo utilizaremos en el Dialplan para la aplicación Voicemail así referirnos a este buzón
– En segundo lugar, la contraseña para acceder al buzón. Tendremos que crear una “extensión” en el Dialplan para que el usuario pueda acceder a su buzón de forma interna. Esto solo es útil si no marcamos la opción de borrado de mensajes del buzón al ser enviados por email
– En tercer lugar, nombre del buzón que luego utilizaremos en variables como VM_NAME
– En cuarto lugar, Email del destinatario de los mensajes de este buzón

Este es un ejemplo muy sencillo, pero a esto podríamos aplicarle un poco mas de complejidad al asunto

[extensiones]
1000 => 9878,Mr. Lenny, lenny@debian.net,,attach=yes|delete=1
– En quinto lugar, iria la dirección del Pager… muy poco utilizado a dia de hoy
– En último lugar, irían opciones especiales. En este caso, decimos que adjunto el mensaje, y lo borre a continuación. Si hemos activado las opciones en el contexto general, ira bien esto.

Si queremos hacer “broadcasting” de mensajes de buzon a varios emails, hay varios métodos pero el que a mi mejor me ha funcionado es hacerlo en combinación a aliases del servidor de correo (en nuestro caso al usar Ubuntu, por defecto, Postfix)

1001 => 8765, Dpto. de Botijos, botijos@nuestroservidor,,attach=yes|delete=1

Nos vamos a /etc/aliases y añadimos
botijos: sr.sanchez@botijoland.com,sr.perez@botijoland.com,sr.alvarez@botijoland.com

Y refrescamos aliases comando: # newaliases

Por ultimo no olvidemos recargar nuestro voicemail.conf #asterisk –rx ‘voicemail reload’

Ahora toca editar nuestro Dialplan para poder utilizar estos buzones recién configurados. Vamos al extensions.conf:

Si queremos por ejemplo hacer que los usuarios puedan dejar mensajes a nuestro contestador tenemos que utilizar la aplicación Voicemail
Ejemplo:

exten => 1000,1,NoOp()
exten => 1000,n,Dial(SIP/1000,30)
exten => 1000,n,Voicemail(1000@extensiones,u)
// En este caso, ponemos el número del buzón que pusimos antes @ el contexto al que pertenecía, adicionalmente ponemos una opción, para que antes de dar el pitido de “empezar a grabar” diga el mensaje de “en estos momentos no nos encontramos, deje su mensaje después de oír la señal”. Aquí tenemos varias, opciones, en vez de utilizar los mensajes por defecto que se pueden encontrar en la carpeta de sonidos /var/lib/asterisk/sounds/ todos los que empiezan por vm- tienen algo que ver con el buzón de voz y estas opciones. Las opciones posibles son:
sin opciones: se escuchan las instrucciones para dejar el mensaje
s: no se escucha nada (útil si queremos poner mensajes personalizados para cada usuario)
su: mensaje de no disponible
u: mensaje de no disponible + instrucciones
sb: mensaje de ocupado
b: mensaje de ocupado + instrucciones

Con esto también podemos jugar con las aplicaciones Playback y Record, para con la opción “s” crear un buzón acorde a las necesidades de un usuario en concreto

Por otro lado vendría la aplicación destinada a escuchar los mensajes guardados si no pusimos la opción de borrado automático: VoicemailMain. Tiene poca historia:
exten => 10001,1,VoicemailMain(1000@extensiones)
El tema es que a partir de ahí vendría un menú relativamente complejo, editable, y demás. Yo personalmente no lo utilizo ya que la función de envío a correo aparte de que me descarga el disco duro, hoy en día a la mayoría del personal le resulta formidable. Aun así, para aquellos que deseen profundizar, les dejo un enlace al manual por si acaso quieren probarlo. Cualquier consulta acerca de esto, no duden en comentármela!

En principio, con todo esto, ya se podrían componer sistemas de Buzón de voz bastante interesantes. Como ven no es demasiado complejo y existen muchas alternativas y opciones. Yo personalmente opino que las opciones de envío a correo, todavía están muy poco elaboradas, pese a que se ha profundizado en ellas. Yo personalmente no he encontrado opciones por ejemplo, de envío CC o CCO (BCC) para envíos broadcasting (lo cual me resultaría muy interesante). Supongo que sería una cuestión de apoyar programando, al proyecto Asterisk. Quien sabe, a lo mejor más adelante nos animamos a ello.

Creando una Operadora Automatica de Coste Cero I

Es curioso observar que el 99,99% de sistemas de operadoras automaticas de las PBX de marcas reconocidas como Alcatel-Lucent, Panasonic, Siemens, el coste de poseer un sistema de operadora automatica, o IVR (interactive voice response), sea directamente proporcional al numero de canales entrantes de voz. Y la pregunta es, ¿realmente estas operadores ofrecen algo mas que no podamos obtener a traves de nuestro magnifico sistema Asterisk? La respusta no solo es negativa, sino que ademas podemos discriminar que vamos a ser capaces a traves de nuestro plan de marcacion de realizar operaciones totalmente casi inimaginables para estas centralitas de alto nivel, al menos, sin una dificultad de alto standing.

¿Pero no se supone que las PBX de marcas reconocidas poseen interfaces de configuracion ampliamente escalables y de relativa facil configuracion? Solo si queremos hacer funciones, que no sobrepasen el nivel del mar.

Y eso es lo que vamos a tratar de hacer hoy, pero sin ir demasiado lejos, solo andando un poco por la arena.

Segun veiamos el otro dia con respecto a los Gateways, y la capacidad de recibir llamadas entrantes, vamos a plantear un nuevo contexto dentro del DialPlan en el que manejemos dichas llamadas a nuestra voluntad.

Partiendo de la base:

[desde-rdsi]
exten => 987654321,1,NoOp()
exten => 987654321,n,Answer
exten => 987654321,n,Goto(operadora,s,1)

Tenemos la instruccion Goto, que nos permite desplazarnos a otro contexto (operadora), marcacion de extension (s) y prioridad (1). Ya hemos hablado sobre las prioridades y los contextos. ahora voy a hacer una breve reseña sobre las marcaciones de extension.

Por un lado existen las marcaciones especiales:

s viene de start, suele ser, la marcacion de inicio de todo contexto, una extension comodin para dejar claras las cosas por regla general.
i viene de invalid, en caso que marquemos una extension que no pertenezca a un contexto, entonces iremos a esta marcacion de extension
t viene de timeout simple, seria el caso de que se acabe el tiempo por una aplicacion que tenga expiracion de tiempo, como WaitExten
T viene de timeout absoluta, existe una variable global (ya veremos variables locales y globales en otro momento) llamada TIMEOUT que establece el tiempo total que se permite mantener una llamada en activo, en el momento que expira este tiempo, entonces saltariamos a la T del contexto que nos encontremos

Por otro lado existen las extensiones normales, y los patrones

Una extension normal simplemente es un numero cualquiera
Un patron viene precedido por un guion bajo  “_” y permite que se puedan crear patrones de posibles extensiones numericas. Informacion detallada sobre esto, la explico en un post mas antiguo

Ahora ya que sabemos lo que necesitamos saber sobre extensiones comenzamos con nuestro contexto de IVR

[operadora]
exten => s,1,NoOp
exten => s,n,Answer()
exten => s,n, GotoifTime(8:00-14:00,mon-fri,*,*?abierto,s,1)
exten => s,n,GotoifTime(16:00-18:00,mon-fri,*,*?abierto,s,1)
exten => s,n,GotoifTime(*,mon-fri,1,jan?festivo)
exten => s,n,Playback(fueradehorario)
exten => s,n,Voicemail(100@default)
exten => s,n,Hangup
exten => s,n(festivo),Playback(festivo)
exten => s,n,Voicemail(100@default)
exten => s,n,Hangup

Esto podria ser la estructura de una eficaz “introduccion” a nuestra operadora automatica. Leyendolo rapidamente, lo que tratamos de hacer es que salte al contexto “abierto” en caso que la llamada se encuentre en horario lectivo de la empresa, o que salte a la etiqueta “festivo” en caso que coincida que es dia de fiesta. En otro caso, lanzara un mensaje de “estamos cerrados”, saltara un buzon de voz para dejar mensajes y colgara, en caso que salte a la etiqueta “festivo”, algo parecido, un mensaje diciendo que es dia festivo en la empresa, buzon de voz y cuelgue.

Realmente esto se podria usar incluso como plantilla para miles de centralitas de PYMES y SOHO y ofreceria una configuracion basica, potente y eficaz, sin tener que andar merodeando en miles de interfaces graficas que pueden dar lugar al error facilmente. Esta claro que este blog esta dedicado a gente especializada en el mundo de la informatica y/o las telecomunicaciones por lo que trabajar sobre una pantalla con fondo negro y letras blancas no deberia ser demasiado drama y mas alla aun, deberia ser una gratificacion excepto en contados casos.

Figura 1: “No exige aprender Linux o Scripting” Como si fuera algo malo

Ahora vamos alla con el detalle. En primer lugar vamos a introducir la aplicacion GotoifTime:

Como vimos con Goto, es equivalente, pero introduciendo una condicion temporal. Para los conocedores de Cron, esto es equivalente.

En primera posicion, especificamos hora o rango horario, incluso varios rangos horarios. Por nuestro ejemplo podriamos haberlo resumido con:

exten => s,n, GotoifTime(8:00-14:00,mon-fri,*,*?abierto,s,1)
exten => s,n,GotoifTime(16:00-18:00,mon-fri,*,*?abierto,s,1)

por

exten => s,n,GotoifTime(8:00-14:00|16:00-18:00,mon-fri,*,*?abierto,s,1). Dos pajaros de un tiro como quien dice.
El segundo parametro, es el dia de la semana, en ingles, los tres primeros caracteres, y ocurre lo mismo que con las horas, rangos, multiples rangos, etc.
El tercer parametro, es el dia del mes y el cuarto, el mes en ingles y los tres primeros caracteres igual. El resto es equivalente a a la aplicacion Goto.

Ademas aqui hemos introducido las etiquetas aparte de los contextos. Una etiqueta se ubica en una parte de la prioridad, esto es util cuando como ocurre en mis ejemplos en vez de poner prioridades del tipo, 1 2 3, etc pongo siempre n considerando lo de n+1 y queremos saltar a otra prioridad sin tener que saber la posicion relativa (esto nos permite la maxima genericidad en nuestros planes de marcacion y la capacidad de insercion futura en casos complejos).

Sobre los ultimos dos parametros, dia del mes y mes, hay que considerar que esto permite mucho “poder” para crear genericidad a lo largo de los años, como son el caso de los dias festivos. En nuestro ejemplo decimos: Si es lunes a viernes y ademas cae el 1 de Enero entonces es festivo. Aunque sea lo que sea realmente es festivo este seria un ejemplo especifico de la posibilidad saltar al contexto dia festivo realmente en estos dias, y si fuera un sabado o un domingo, como ya es festivo de por si, que de el otro mensaje (El de cerrado simplemente) . Opciones hay muchas y esto quedaria a nuestra libertad.

Mas alla aun, asterisk 1.8 tengo entendido que incluso existe la posibilidad de crear calendarios con Google Calendar y desde ahi especificar los dias festivos y toda la informacion relativa a tiempos. Hay mas informacion aqui, y esto nos ofreceria un nivel de potencia a bajo coste de complejidad para nuestro IVR que ninguna otra central se acercaria lo mas minimo. Ahora ya podemos decir que estamos sobre el nivel del mar, y eso que no hemos empezado siquiera en este mundillo.

Por otro lado, tenemos la aplicacion Playback. Simplemente reproduce un archivo de musica que tengamos en la carpeta correspondiente en funcion de nuestro lenguaje definido. Los sonidos se encuentran en /var/lib/asterisk/sounds/

Finalmente esta la aplicacion Voicemail, que basicamente llama a otro archivo de musica (“deje su mensaje despues de oir la señal”) y guarda el mensaje de voz en el buzon especificado (100) del contexto por defecto (@default). Todo esto podemos verlo y configurarlo en el archivo de configuracion voicemail.conf que seguramente veremos en otro momento.

Y ahora ¿que ocurre con las llamadas que van al contexto “abierto”?

Vamos a hacer algo sencillito en abierto para terminar por hoy, y mas adelante intentaremos profundizar aun mas en todo esto.

[abierto]
exten => s,1,NoOp
exten => s,n,Background(listadistribucion)
exten => s,n,WaitExten(20)

exten => 1,1,NoOp
exten => 1,n,Goto(comercial,s,1)

exten => 2,1,NoOp
exten => 2,n,Goto(postventa,s,1)

exten => t,1,NoOp
exten => t,n,Goto(telefonista,s,1)
exten => t, n,Goto(s,1)

Voy a leerlo: primero, saltaria un mensaje, que diria “Bienvenido a nuestra empresa, Marque el 1 para hablar con Comercial o Marque el 2 para hablar con Posventa, en otro caso espere y le pondremos con un Agente”. En caso de marcar el 1, le mandaria al contexto comercial, y en caso de marcar el 2, a postventa. En caso de “Timeout simple” le mandaria al telefonista.

Aqui solo tenemos dos aplicaciones que no vimos hasta el momento:

Background es equivalente a Playback pero deja a la espera de marcacion de una extension. Podemos interrumpir el background si marcamos teclas en el telefono y saltaria a la extension del contexto marcada (hay mas opciones complejas, como saltar a extensiones de otros contextos pero no voy a entrar en detalles)

Por otro lado Waitexten, basicamente establece el tiempo que tenemos para marcar una extension antes de ir a la extension especial “t”.

Parece sencillo, y lo es. Asi que invito a hacer mil combinaciones con toda esta información para crear posibles IVR sencillitos que cumplan una funcion que para la mayoria de las PBX del mercado suele ser bastante compleja y obliga a pasar por miles de secciones de la interfaz grafica. Por esto, es suficiente por hoy. Seguiremos informando como suele decirse

Introduciendo un Proveedor SIP: Parte 2

Tras la migracion, y aun a la espera del retorno de la tarjesta TDM410P enviada en garantia, hoy voy a hacer una pequeña explicacion de las ultimas modificaciones introducidas a nuestro sistema Asterisk, concretamente a nivel de DialPlan, para en detalle, el funcionamiento del Proveedor SIP que configuramos el otro dia y por otro lado, algunos retoques para darle un poco mas de nivel a nuestro sistema, como una pequeña operadora automatica de pruebas.

Realmente aqui se vera gran parte del codigo contenido en nuestro fichero “extensions.conf” y un poco la explicacion de cada atributo.

[operadorip]
exten => 851123456,1,NoOp()
exten => 851123456,n,Goto(s,1)
exten => sirlouen,1,NoOp()
exten => sirlouen,n,Goto(s,1)

Si recuerdan, el otro dia pusimos en el contexto del provedor SIP dentro del sip.conf, llamado “operadorip”. Este contexto vendra directamente aqui.

La primera vez que hable del DialPlan no explique exactamente a que se referia cada argumento de la linea exten=>

En primer lugar, exten, se refiere como su nombre indica, a la extension marcada a la que va a hacer referencia como primer argumento. Esto es lo mas extendido y utilizado por defecto. En este caso, la extension, hablamos del numero DDI que nos ofrece el operador IP ya que de alguna forma es como lo reconocera como primera “entrada” nuestra centralita. En algunos casos, el proveedor IP te ofrece un numero de usuario adicionalmente, y este numero de usuario tambien lo entrega el operador IP sustituyendo al numero DDI, de forma casi aleatoria segun comprobe tras diversas pruebas. Por eso decidi poner las dos posibilidades.

Como segundo argumento, es el numero de prioridad en la lista de ejecucion. Lo tipico es poner en la primera linea el 1, en la segunda el 2, etc. Pero si ponemos en la primera el 1 y luego la n, significa que aumentamos el contador de prioridad linealmente, 1, n+1 (2), n+1 (3), etc. Esto es util si por ejemplo en un futuro tenemos intencion de meter mas lineas intermedias, no tengamos que cambiar el numero de prioridad a toda la secuencia completa, algo engorroso y que puede dar lugar a errores.

El tercer argumento hace referencia a la funcion que va a cumplir esa linea. En mi caso, siguiendo un buen consejo que me dieron, lo ideal seria poner NoOp (sin operacion), para poder asi asignarle el elemento 1 por defecto. Esto es una buena practica en general ya que si luego creamos Macros (equivalente a plantillas para secuencias del Plan de Marcacion), esto hace que exista cierta uniformidad y estandarizacion. Tampoco es crucial escribir asi, pero desde que se creo el Copy & Paste tampoco supone una gran inconveniencia y nos aportara mas que nos rebajara.

Los siguientes Argumentos en embos casos, son condicionales GO TO, tipicos en programacion. La funcion GoTo recibe 3 parametros siendo como primer parametro, un contexto, si solo se dan dos, se conserva en el contexto en que nos encontremos. El segundo, seria la posicion de marcacion dentro de ese contexto. S viene a ser la posicion de inicio por defecto. Donde suele entrar todo (hace referencia a Start, comienzo) al entrar en un contexto. Finalmente indicamos el lugar de la prioridad donde queremos entrar. Tambien con la funcion Goto podriamos pasar 1 solo argumento, esto es el lugar dentro del a prioridad (y consideraria la posicion de marcacion y el contexto donde actualmente nos encontrasemos), tambien podemos pasar una bandera asociada a un nivel de prioridad como veremos mas adelante.

Con esto, de alguna forma, si nos llaman a nuestro numero DDI, “ya estariamos dentro de la centralita”, ahora tocaria a traves de un Contestador Automatico, manejar esta llamada

exten => s,1,NoOp()
exten => s,n,Answer
exten => s,n,Background(menu)
exten => s,n,WaitExten(20)

Esto es bastante sencillo. Igual que vimos con anterioridad, recogemos la llamada con Answer, y con Background ponemos un sonido que tendremos registrado en nuestro directorio /var/lib/asterisk/sounds.
Hay dos formas de crear sonidos
1. A traves de una marcacion con la funcion Record, grabariamos nuestros propios sonidos
2. Directamente introduciendo la pista de audio en la carpeta indicada con el nombre en cuestion y segun el formato .gsm, .wav, etc que tengamos especifcado dentro de los codecs soportados en este contexto.
Finalmente tenemos la funcion WaitExten que basicamente realiza la operacion de espera a que se marque un digito durante los segundos pasados como parametro. Este digito entra como marcacion DTMF y como comente en otra ocasion, aqui se originaron problemas por parte del operador IP, a raiz de las malas latencias, que al final consegui solucionar en el fichero de configuracion de disposistivos SIP utilizando el modo DTMF “inband”
exten => 1,1,NoOp()
exten => 1,n,Playback(ext1000)
exten => 1,n,Goto(extensiones_internas,1000,1)
exten => 2,1,NoOp()
exten => 2,n,Playback(ext1001)
exten => 2,n,Goto(extensiones_internas,1001,1)
Una vez marcado el digito por DTMF iriamos a la posicion de marcacion, en este caso pongo dos ejemplos sencillos, lo unico especial, la funcion Playback que a diferencia de Background no espera una marcacion, simplemente reproduce un mensaje y continua hasta la siguiente orden. En este caso, cambiamos de contexto y ya finalmente nos vamos a nuestro contexto “privado” donde estan ubicadas las extensiones de nuestra oficina tal y como configuramos con anterioridad.
Ahora vendria la otra perspectiva, desde “dentro” hacia el exterior a traves del proveedor SIP.
En este caso por motivos logicos de “seguridad” no nos interesaria que alguien pudiera acceder a traves de las marcaciones DTMF en el mismo contexto “operadorip” y ser capaz de llamar al exterior. Por esto, la idea es que esto solo pueda marcarse desde el contexto “privado” donde se encuentran nuestras extensiones.
En este caso la marcacion es un tanto especial y tenemos que introducir nuevos conceptos:
;Salida de llamadas Nacionales
exten => _[689]XXXXXXXX,1,NoOp()
exten => _[689]XXXXXXXX,n,Dial(SIP/${EXTEN}@netelip,30)
exten => _[689]XXXXXXXX,n,Hangup()
Como podemos ver, aqui aceptamos un total de 9 posiciones. Bueno parecen mas, pero aqui explico el formato especial de marcacion que he tenido en cuenta para este caso:
En primer lugar, si vamos a usar caracteres especiales como X,N o Z necesitamos poner delante la barra baja.
En segundo lugar, observamos los tres valores 6,8,9 contenidos entre corchetes. Al estar contenidos entre corchetes significa los posibles valores que puede tomar el primer digito, solo el 6 (moviles), 8 (numeros geograficos virtuales) y 9 (numeros geograficos de España). Tambien podriamos tener un guion tipo [67-9] en este caso estariamos considerando los valores 6,7,8 y 9 seria lo mismo que [6-9]
En tercer lugar tenemos digitos especiales. X significa cualquier valor entre 0 y 9, Z entre 1 y 9 y N entre 2 y 9. En este caso seguramente seria mas eficaz separar los moviles y los fijos dado que podriamos en un segundo nivel restringir las llamadas a numeros especiales tipo 902, 901, etc eliminando la posibilidad con [89]ZXXXXXXX. Aqui tenemos tantas posibilidades como queramos.
Una vez marcada esta secuencia, nos encontramos con la Funcion Dial, que al igual que utilizado para marcar extensiones en este caso con la variable ${EXTEN} recogemos lo marcado en la posicion de marcacion y lo “enrutamos” a traves del contexto sip indicado tras la @ en este caso nuestro Proveedor IP. El ultimo parametro 20, es el tiempo que esperara tras marcar para que recoja tono la llamada, en otro caso colgara.
Entendido esto podriamos crear sistemas de marcacion todo lo complejo que se nos ocurriesen. Y muy util para la creacion de plantillas, y para la generacion de extensiones de manera semi-automatica puesto que por parte del dialplan no seria necesario apenas escribir codigo si el patron de las extensiones es equivalente.
Con esto doy una breve revision de la interrelacion de un proveedor IP y el Plan de Marcacion de nuestro sistema para poder darle uso. Pero el Dial Plan tiene mucha miga por dentro, miles de funciones. Seguire en sucesivos articulos poniendo mas ejemplos sobre posibles opciones que se me ocurran y que mas concretamente sean muy utiles en un entorno de produccion/oficina.