Terminado el curso de Vicidial

12 Sep

Durante los últimos 4 días estuve en Tampa, FL tomando un curso acerca de Vicidial, una suite open source con marcador predictivo para call centers basados en Asterisk. El curso fue impartido por Matt Florell, el creador del software, y durante las horas que estuvimos en el salón de clases pude aprender y corroborar muchos detalles interesantes sobre este sistema que aunque lleva varios años en el mercado, pocos se han dado a la tarea de conocerlo.

El curso se divide en 2 partes: el Manager y el Admin. Durante el curso de Manager se da una explicación a detalle de como utilizar la interfaz web de Vicidial: como se crean campañas de entrada y salida, como se cargan registros, como se configuran carriers para enviar las llamadas, como podemos controlar la distribución de llamadas entre los agentes, etc. Todas y cada una de las opciones de las más de 200+ que hay para alterar en la suite fueron vistas y explicadas. A pesar de que en la interfaz web es posible leer la documentación HTML que viene con el software, muchas veces las cosas no se comprenden tan bien como cuando puedes debatirlas, y este fue uno de los casos. Inclusive las explicaciones ayudaron a visualizar escenarios que no habiamos contemplado, pero que pueden resultar muy útiles para cualquier callcenter.

En la segunda parte del curso se vieron detalles mucho más técnicos: como instalar el sistema, como hacer troubleshooting, cuales son las causas comunes de que un sistema de estos falle (el famoso time synchronization error o el there are no available sessions), así como muchas otras características avanzadas que el mortal promedio no ocupa, como el uso de los APIs, la captura extendida de números telefónicos, etc. Al final terminamos con una instalación de Vicidial en cluster (lo que ofrece máxima escalabilidad al sistema) y corrimos pruebas de rendimiento para comprobar que todo estuviera bien y supiéramos hasta donde podemos llegar con él. En general, un curso muy teórico y con mucha información. Debo reconocer que mis favoritos fueron los últimos dos días, pues fue cuando realmente tuve oportunidad de jugar con el sistema.

Vicidial hoy en día es un producto que deja muy por atrás a toda la competencia, tanto en funcionalidades como en precio. Aquellos que han probado el módulo de callcenter de Elastix puedo decirles fácilmente que no tiene nada que ver con Vicidial: Elastix fue pensado como un PBX para empresa, no como medios para un callcenter, y Vici está muy por encima en funcionalidades. ¿Acaso el precio podría hacer la diferencia? No, porque es el mismo que con el resto del open source: ¡gratis!, así que tampoco es necesaria una inversión millonaria en sistemas como Avaya o Cisco que a pesar de ser propietarias, se quedan cortos en características.

En mi opinión personal, el único problema que le veo a un software como Vici es precisamente su mayor fortaleza: el grado de complejidad que tiene lo hace para alguien sin conocimientos resulte una tarea muy complicada el tratar de echar a andar una campaña con él. Sin embargo, una vez que se libra esa curva de aprendizaje, los que ahora lo conocemos sabemos que es bastante sencillo de ocupar, y que pueden hacerse cosas geniales con él. Repetiré lo que les digo a mis alumnos del curso de Asterisk: el límite de lo que puedes hacer, es la capacidad del administrador.

Para más información sobre este software, visiten vicidial.org. Si requierieras apoyo profesional para una implementación de Vicidial para un callcenter, por favor utiliza nuestro formulario de contacto.

¡Suerte!

Como eliminar el eco en llamadas: instalando OSLEC y usando fxotune

7 Sep

El eco en una señal de telefonía ocurre cuando tenemos 2 conductores a diferentes impedancias. El desacople de las mismas ocasiona que la señal se refleje y se perciba por nuestro cerebro como 2 señales diferentes. Si el eco es superior a 150ms, comienza a volverse molesto ya que como humanos nos distrae de la conversación que estamos teniendo.

En un sistema 100% VoIP el eco no existe. Definitivo: no existe. Sin embargo, dado que aún ocupamos medios analógicos para poder nosotros enviar o recibir el audio (micrófonos y altavoces), es en estos dispositivos donde el eco puede ocurrir. El punto más común donde se produce el eco es en el medio que ocupemos para conectarnos con medios 100% analógicos, como la línea telefónica, así que es responsabilidad de nuestras tarjetas o gateways, hacerse cargo de cancelar este eco, ya sea mediante hardware o software (recuerden que en VoIP, la voz al final son datos, y los datos pueden manipularse por software).

Para poder manipular el eco en Asterisk tenemos 2 opciones:

  1. Hardware: es la más cara de las opciones, ya que nos exige comprar hardware dedicado a esta función. Sin embargo, es la de mejor rendimiento ya que libera al CPU de esta carga extra.
  2. Software: justo lo contrario, es la opción más económica, pero depende del CPU para hacer el procesamiento.

Para opciones de hardware podemos comprar tarjetas que soporten esta característica. En tarjetas Sangoma podemos ir por los modelos que tengan la letra D (como la B600DE, A200DE, A101DE). El problema con estas tarjetas es que no son actualizables, es decir, no podemos comprar el módulo de cancelador de eco después. Las tarjetas Digium tienen la ventaja de que podemos adquirir el módulo de cancelador de eco por separado, asi nuestra inversión está asegurada.

En este artículo nos centraremos en las soluciones para software, ya que la mayoría de nosotros tiene equipos que no cuentan con el módulo en HW necesario para lograr esta función, y para hacerlo, primero haremos la instalación de OSLEC (Open Source Line Echo Canceller), la cual, tiene que ser compilada dentro de DAHDI.

Empezando con el trabajo: primero necesitamos conseguir el código fuente de DAHDI y también el código fuente de Wanpipe (los drivers de Sangoma que contienen la referencia a OSLEC).

cd /usr/src
wget http://downloads.asterisk.org/pub/telephony/dahdi-linux-complete/releases/dahdi-linux-complete-2.4.1.2+2.4.1.tar.gz
wget ftp://ftp.sangoma.com/linux/current_wanpipe/wanpipe-3.5.22.tgz
tar -zxf dahdi-linux-complete-2.4.1.2+2.4.1.tar.gz
tar -zxf wanpipe-3.5.22.tgz

Quizá se pregunten: ¿por qué descargar wanpipe si lo podemos conseguir en el código fuente de Linux? Simplemente porque wanpipe es más pequeño y tarda menos en descargarse.

Luego, creamos las carpetas necesarias dentro del código de DAHDI y copiamos la parte de OSLEC que necesitamos:

cd /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers
mkdir staging
cp -r /usr/src/wanpipe-3.5.22/OSLEC/echo staging

En este punto, hay 2 archivos que debemos de modificar:

/usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/staging/echo/Kbuild
/usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/Kbuild

Empezamos por el primero (el cual está vacio). Solo necesita que agreguemos una línea en su interior:

#
# Archivo /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/staging/echo/Kbuild
#
obj-m += echo.o

El segundo archivo si tiene contenido. Buscamos un contenido similar a este:

# Archivo: /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/Kbuild

# Only enable this if you think you know what you're doing. This is not
# supported yet:
#obj-m += dahdi_echocan_oslec.o
#
# A quick and dirty way to build OSLEC, if you happened to place it
# yourself in the dahdi source tree. This is experimental. See README
# regarding OSLEC.
#obj-m += ../staging/echo/

Quitamos el comentario a las 2 lineas de código para dejarlo así:

# Archivo /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/Kbuild

# Only enable this if you think you know what you're doing. This is not
# supported yet:
obj-m += dahdi_echocan_oslec.o
#
# A quick and dirty way to build OSLEC, if you happened to place it
# yourself in the dahdi source tree. This is experimental. See README
# regarding OSLEC.
obj-m += ../staging/echo/

Procedemos a recompilar DAHDI desde nuestra carpeta /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1


cd /usr/src/dahdi-linux-complete-2.4.1.2+2.4.1
make
make install

2 passos más: editamos /etc/dahdi/system.conf

#
# Archivo /etc/dahdi/system.conf
#
# Tomen en cuenta reemplazar sus canales por los de su equipo
# En este ejemplo tengo una tarjeta de 4 puertos FXO
fxsks=1-4
echocanceller=oslec,1-4

Y aplicamos los cambios desde el CLI de Linux:

dahdi_cfg -vv
DAHDI Tools Version - 2.4.0.1

DAHDI Version: 2.4.0.1
Echo Canceller(s): OSLEC
Configuration
======================

Channel map:

Channel 1: FXS Kewlstart (Default) (Echo Canceler: oslec) (Slaves: 01)
Channel 2: FXS Kewlstart (Default) (Echo Canceler: oslec) (Slaves: 02)
Channel 3: FXS Kewlstart (Default) (Echo Canceler: oslec) (Slaves: 03)
Channel 4: FXS Kewlstart (Default) (Echo Canceler: oslec) (Slaves: 04)

Si todo carga sin errores, ¡listo! tenemos habilitado el cancelador de eco OSLEC, que es considerablemente mejor contrarestando el eco que el default de MG2.

Estos pasos son bastante buenos para reducir el eco de nuestra línea, pero si aún así tenemos problemas, podemos usar fxotune para virtualmente, eliminar el eco remanente. Es muy sencillo de usar. El procedimiento sería el siguiente:

  1. Detenemos Asterisk para que los canales DAHDI no estén en uso
  2. Creamos el archivo /etc/fxotune.conf (se crea automáticamente usando el comando fxotune -i)
  3. Cargamos los coeficientes encontrados cada vez que arranque el sistema
  4. Reiniciamos Asterisk

Visto en código sería algo así:


/etc/init.d/asterisk stop
fxotune -i # Esto puede demorar algunos minutos
echo 'fxotune -s' >> /etc/rc.local
/etc/init.d/asterisk start 

Nota final: El fxotune debe ser ejecutado cuando Asterisk NO está corriendo. En el ejemplo anterior, estoy agregando el fxotune -s al rc.local para que cargue en automático, pero esto hará que tras el re-arranque, se ejecute hasta después de que Asterisk ya inició (lo cual no está bien). Si queremos asegurarnos que cargue siempre, podemos agregar al rc.local las instrucciones para que Asterisk se detenga, se ejecute fxotune y luego re-arranque Asterisk. Hay muchas maneras de hacer esto, pero eso escapa a la intención de este artículo.

Siguiendo todos estos pasos, el eco debe quedar prácticamente eliminado. Hasta el momento he hecho instalaciones que han mantenido eco con uno de estos pasos, pero nunca alguno que haya persistido con los 2.

¡Suerte!

Elastix hack: Usar los Cisco SPA5XX con el endpoint configurator de Elastix

19 Jul

En numerosas ocasiones he usado el Endpoint Configurator de Elastix para facilitar la configuración de múltiples teléfonos de manera rápida y sencilla. Sin embargo, recientemente que empecé a ocupar los teléfonos Cisco SPA502G y SPA504G me topé con que Elastix no los reconoce (o al menos, no directamente), así que no podía usar el configurador automático con ellos.

Los teléfonos de la serie SPA provienen de Linksys, el fabricante de equipo de red para SoHo que Cisco adquirió, pero estos a su vez provienen de Sipura, que es un fabricante que pocos conocen y que hace mucho tiempo, Linksys compró. La configuración entre los diferentes modelos no ha cambiado mucho a pesar de los años, así que un Cisco SPA504G se configura prácticamente igual que un Linksys SPA942, y esos SI son detectados por el configurador de Elastix.

Entonces… ¿Cómo hacemos para que Elastix detecte estos nuevos modelos?

Una forma muy sencilla es engañando al configurador, haciéndolo creer que se tratan de SPA942. Para hacerlo, solo tenemos que agregar las MACs de Cisco dentro del archivo /var/www/db/endpoint.db (el cual viene en formato de sqlite). El código sería el siguiente:

sqlite3 /var/www/db/endpoint.db
sqlite> INSERT INTO "mac" VALUES(45, 4, 'C8:9C:1D', 'Cisco - SPA504G');
sqlite> INSERT INTO "mac" VALUES(46, 4, 'E0:5F:B9', 'Cisco - SPA504G');
sqlite> .quit

Estas 2 series de MACs, la E0:5F:B9 y la C8:9C:1D son las que por experiencia he encontrado que estos nuevos teléfonos tienen. ¿Qué quieren decir los otros campos?

  • El ’45’ es el número de la fila. Por default vienen otros 44 registros en la tabla mac, pero podemos reemplazarlos por cualquier otro número (como 100 o 101)
  • El ‘4’ es el que le dice a Elastix que el teléfono encontrado es un Linksys
  • El ‘E0:5F:B9’ o ‘C8:9C:1D’ corresponde al inicio de la MAC del teléfono. Mismos modelos suelen tener el mismo comienzo de MAC
  • El último campo es solo una descripción de lo que se está agregando. Esto no se usa, es solo para que los humanos entendamos de que se trata la fila.

Tras hacer el cambio, podemos re-ejecutar el endpoint y obtendremos algo como esto:

Esto nos indica que nuestros teléfonos ya fueron reconocidos, así que podemos aplicar la configuración de la extensión para configurar nuestros nuevos teléfonos.

¡Suerte!

Protege tu Asterisk de ataques usando fail2ban

7 Jul

En ocasiones anteriores he hecho la mención de fail2ban, una herramienta escrita en Python que analiza logs del sistema y responde en caso de que ciertas condiciones se cumplan, por ejemplo, 5 intentos de contraseña SSH equivocada en un periodo de 10 minutos. Dada la proliferación de ataques a equipos Asterisk para tratar de hacer llamadas de larga distancia, tiene sentido que ocupemos esta herramienta para protegernos de los amantes de lo ajeno.

Ahora bien, ¿cómo configuramos esta herramienta para que nos evite los cargos de miles de dólares en llamadas fantasmas?

Primero, lo instalamos. En Debian podemos usar el mundialmente reconocido apt-get:

apt-get install fail2ban

O, si tenemos Centos, primero asegurémonos de que tengamos EPEL (un repositorio que nos da acceso a mucho software útil) y luego instalamos fail2ban:

rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm 
yum -y install fail2ban

Fail2Ban se configura en 2 partes básicas:

  • /etc/fail2ban/jail.conf – Define que logs monitorear y que hacer en caso de que una regla se cumpla
  • /etc/fail2ban/filter.d/<filtro> – Definimos las reglas de coincidencia para analizar los logs

Editemos el archivo jail.conf y agreguemos esto hasta abajo:

[asterisk-iptables]
enabled  = true
filter   = asterisk
action   = iptables-allports[name=ASTERISK, protocol=udp, port=5060]
sendmail-whois[name=ASTERISK, dest=micorreo@algunmail.com, sender=fail2ban@example.org]
logpath  = /var/log/asterisk/full
maxretry = 5
findtime = 600
bantime = 10800

Lo que estamos especificando es lo siguiente:

  • La regla (jail) se llama asterisk-iptables
  • El filtro a usar debe existir en /etc/fail2ban/filter.d/asterisk.conf
  • Cuando se active la regla, usaremos la acción iptables-allports, la cual bloquea a nivel de iptables. Nosotros le estamos indicando que cierre el acceso al puerto UDP 5060, y luego que haga uso de la acción sendmail-whois, la cual me enviaria a mi correo electrónico la notificación del bloqueo, además de enviarme información de whois de la IP que se bloqueó.
  • El archivo log a monitorear es el /var/log/asterisk/full (ojo, dependiendo de tu sistema, el log puede ser diferente, ajústalo acorde)
  • Se permiten un máximo de 5 fallos en 10 minutos antes de activar la protección. Es decir, se permiten un máximo de maxretry intentos en findtime segundos
  • Al activarse el bloqueo, se hará por 3 horas o bien, 10800 segundos (bantime)

En esta liga encuentras el manual oficial para el jail.conf.

Ya definido el jail, necesitamos crear el filtro que atrapará los ataques. Esto se define (de acuerdo a lo que especificamos arriba) en el /etc/fail2ban/filter.d/asterisk.conf (los valores con # son comentarios, solo se dejan por referencia)

[INCLUDES]

# Read common prefixes. If any customizations available -- read them from
# common.local
#before = common.conf

[Definition]

#_daemon = asterisk

# Option:  failregex
# Notes.:  regex to match the password failures messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching and is only an alias for
#          (?:::f{4,6}:)?(?P<host>S+)
# Values:  TEXT
#

failregex = Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Wrong password
       Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - No matching peer found
       Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Device does not match ACL
       Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Username/auth name mismatch
       Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Peer is not supposed to register
       NOTICE.* <HOST> failed to authenticate as '.*'$
       NOTICE.* .*: No registration for peer '.*' (from <HOST>)
       NOTICE.* .*: Host <HOST> failed MD5 authentication for '.*' (.*)
       VERBOSE.* logger.c: -- .*IP/<HOST>-.* Playing 'ss-noservice' (language '.*')

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Se observa que estamos tratando de atrapar a los siguientes:

  • Usuarios que ingresan su contraeña SIP incorrectamente
  • Usuarios que intentan usar un usuario SIP que no existe
  • Usuarios que no cumplen con los parámetros permit y deny del sip.conf
  • Usuarios que su auth username no coincide con su username
  • Usuarios que tratan de registrarse con perfiles que son fijos (es decir, que no tienen host=dynamic)
  • Usuarios que no cumplen con los criterios de autenticación
  • Usuarios que marcan hacia números que no existen (esto es común en Elastix/FreePBX cuando deshabilitamos recibir llamdas anónimas)

En esta liga encontramos el manual de los filtros de fail2ban.

Finalmente, solo nos queda activar el servicio. En Debian ya quedó instalado automáticamente, solo tenemos que arrancarlo:

/etc/init.d/fail2ban start

En CentOS, tenemos que habilitar el autoarranque para que inicie al arrancar el equipo:

chkconfig --add fail2ban
chkconfig fail2ban on
/etc/init.d/fail2ban start

Fail2ban es un excelente apoyo contra ataques que dejan registros en logs y no solo nos sirve para Asterisk, también para SMTP, SSH, HTTP o cualquier otra cosa que queramos monitorear. Esto, en conjunción con buenas prácticas de seguridad para Asterisk, nos darán un sistema más confiable y menos propenso a sufrir daños por parte de atacantes.

¡Suerte!

 

Mantente actualizado con los cambios en Asterisk

7 Jul

Si alguno de ustedes es como yo, muy probablemente les guste batallar con los betas. Suelo ser de aquellos que en cuanto sale una nueva versión corro a adoptarla, no importándome los problemas de estabilidad o soporte extra que esto conlleva. Sin embargo, hay algunos casos en los que definitivamente no es posible sacrificar la confiabilidad de un sistema, aunque esto nos traiga nuevas funcionalidades.

En sus inicios yo literalmente brinqué de Asterisk 1.0 a 1.2 sin pensarlo, lo mismo 1.2 a 1.4, y esto es hablando en entornos en producción (mala idea, yo sé, afortunadamente funcionó bien), pero cuando quise hacer lo mismo para 1.6 me paré en seco: mis sistemas se caían sin razón aparente, muchas cosas cambiaron, el AgentCallbackLogin dejó de existir y en general fue una experiencia poco placentera, al grado que decidí quedarme con 1.4 (y hasta la fecha) lo he seguido haciendo.

Con la reciente noticia de que Asterisk 1.4 alcanzó su último maintenance release, el momento de hacer el cambio es ahora. Muchos colegas en la materia opinarán que la 1.6 nunca acabó de ser lo que se esperaba. Yo digo a mis alumnos en los cursos (bajo opinión personal) que Asterisk 1.6 fue el Windows Vista de Digium: para cuando ya se corrigieron la mayor parte de los detalles que tenía, salió Asterisk 1.8, así que el salto sería directo, de 1.4 a 1.8, sin pasos intermedios. Opino yo: ¿para que hacer 2 migraciones cuando se puede hacer una sola?

Cuando nos queremos actualizar, leer los changelogs desde 1.4 a 1.8 puede resultar abrumador: simplemente son demasiados cambios para darnos cuenta de que tanto es lo que tenemos que mover en nuestros planes de llamadas y nuevos campos de configuraciones. Afortunadamente, existe la página de Asterisk Up-to-speed.

En este sitio están concentrados todos los cambios entre versiones 1.4 –> 1.6.0 –> 1.6.1 –> 1.6.2 –> 1.8, de manera que resulta mucho más fácil darle una leida para ver que tanto cambio conforme a lo que usamos, así como aprender cuales son las nuevas funcionalidades  sin tener que repasar todo el manual de aplicaciones. Es una referencia literaria bastante buena y fácil de usar y se las recomiendo a todos aquellos que como yo, estuvieron muy cómodos con la versión 1.4 y decidieron evitar en lo más posible el salto entre versiones.

Recuerden que no hay día que no llegue ni plazo que no se cumple. Si no lo han hecho, conviene que vayan invirtiendo tiempo en planear sus migraciones. Mejor pensarlo bien cuando hay tiempo, y no cuando se tenga la presión de hacer una nueva instalación.

¡Suerte!

Como convertir archivos de sonido y musica en espera para Asterisk

6 Jul

Muchas veces me han pregunado si Asterisk soporta MP3 como música en espera: la respuesta es si y no. Debo decir que si porque en efecto, con el módulo format_mp3 se pueden reproducir MP3, pero debo decir no porque solamente se soportan los de bitrate constante (y hoy en día, prácticamente todos son de bitrate variable, o VBR), además de que el consumo de CPU causado por el transcoding realmente puede afectar al sistema.

Entonces, ¿cómo podemos hacer para convertir nuestra colección favorita de audio MP3 a wav, gsm, ulaw o cualquier otro de los formatos que Asterisk soporte? El mecanismo es más sencillo de lo que se cree, siempre y cuando se tengan los conocimientos mínimos de Linux para hacerlo.

  1. Si tu música origen es MP3, necesitas instalar SoX con soporte para MP3. Aquí un tutorial (en inglés) de como hacerlo. Si tienes Debian, es tan sencillo como usar:
    [codesyntax lang=»bash»]

    apt-get install sox libsox-fmt-mp3

    [/codesyntax]
    Si tu música ya está en un formato que Asterisk soporta (ej. wav mono a 16-bit 8khz), brinca al paso 3

  2. Ya con el soporte para MP3, necesitas convertir tus MP3 a un formato inicial que Asterisk pueda usar. Te recomiendo que si usas Asterisk 1.8+, los conviertas a wav de 16khz. Para todo lo demás, usa wav de 8khz. Estos son los comandos que usarías (dentro de la carpeta donde están tus MP3):
    [codesyntax lang=»bash»]

    # Para Asterisk 1.8+
    for i in `ls *.mp3`
    do sox $i -r 16000 -c 1 -s -w `echo $i|cut -d. -f1`.wav
    rename 's/.wav/.wav16/' *.wav
    done
    # Para Asterisk menor a 1.8
    for i in `ls *.mp3`
    do sox $i -r 8000 -c 1 -s -w `echo $i|cut -d. -f1`.wav
    done

    [/codesyntax]

  3. Dependiendo de la versión que hayas usado, ahora debes tener una carpeta con archivos .wav o .wav16 (Asterisk 1.8 soporta wavs en wideband que se escuchan mucho mejor si tu teléfono soporta codecs HD, como el g722). Lo que necesitas hacer es convertir estos archivos wav al formato que tu quieres (ejemplo: gsm). Para este paso, te recomiendo hagas un script que te facilite la labor. Por ejemplo: convierte.sh
    [codesyntax lang=»bash» tab_width=»3″ title=»convierte.sh»]

    #!/bin/bash
    for i in `find $1 -name "*.$2"`
    do
       j=`echo $i | cut -d . -f 1`
       asterisk -rx "file convert $j.$2 $j.$3"
    done

    [/codesyntax]

  4. No te olvides de darle permisos de ejecución al script con chmod 755 convierte.sh
  5. El último paso es el más sencillo: invocar al recien creado script. Puedes ejecutarlo de la siguiente manera:
    [codesyntax lang=»bash»]

    ./convierte.sh /var/lib/asterisk/moh wav gsm

    [/codesyntax]

Lo argumentos que el script recibe son:

  1. La carpeta donde se encuentran tus archivos (en formato wav)
  2. El formato de los archivos iniciales (los que sox te entregó)
  3. El formato de los archivos finales (gsm, ulaw, g722, ilbc, etc)

El resultado es que tendrás una carpeta con varios archivos (los originales MP3, los intermedios wav y los finales en el codec que escojas). Puedes convertir a cuantos codecs quieras siempre y cuando Asterisk los soporte.

Estos pasos también son válidos si tienes tus archivos de audio en un codec (en la carpeta /var/lib/asterisk/sounds) y quieres convertirlo a otro codec completamente diferente.

¡Suerte!

 

Respaldando la base de datos de configuración de Elastix/FreePBX por SSH

27 Jun

Una gran ventaja que tenemos en Linux es la facilidad de crear procesos automatizados que nos ayuden a ejecutar tareas cotidianas. Para nuestros usos comunes como administrador de equipos basados en Asterisk/Elastix/FreePBX, puede ser una labor cotidiana respaldar la configuración alojada en bases de datos de MySQL.

SSH nos permite ejecutar comandos en servidores Linux remotos y traernos el resultado al mismo tiempo, por lo que resulta ideal para realizar un respaldo en un equpo distante y almacenarlo en nuestro equipo Linux loca. El comando para hacerlo sería el siguiente (asumiendo que usamos la contraseña default de MySQL en nuestro equipo remoto):

[codesyntax lang=»bash»]

ssh 192.168.1.100 "mysqldump -peLaStIx.2oo7 --databases asterisk | gzip -9" > respaldo.sql.gz

[/codesyntax]

El comando de arriba se encargará de hacer un dump de la BD asterisk. Si quisiéramos traernos también el CDR, hariamos lo siguiente:

[codesyntax lang=»bash»]

ssh 192.168.1.100 "mysqldump -peLaStIx.2oo7 --databases asterisk cdr | gzip -9" > respaldo.sql.gz

[/codesyntax]

O si quisiéramos traernos TODAS las bases de datos:

[codesyntax lang=»bash»]

ssh 192.168.1.100 "mysqldump -peLaStIx.2oo7 --all-databases | gzip -9" > respaldo.sql.gz

[/codesyntax]

Hay que tomar en cuenta que estamos asumiendo lo siguiente:

  • La IP de nuestro servidor remoto es 192.168.1.100. Hay que reemplazar esta por la IP real de nuestro equipo del que queramos copiar el respaldo
  • El password default del usuario root del MySQL remoto es eLaStIx.2oo7. Nuevamente, hay que reemplazar este por el correspondiente al servidor

Adaptando este comando podemos prácticamente hacer cualquier tipo de respaldo remoto. Si agregamos la conexión mediante llaves públicas y privadas, podemos dejar estas actividades programadas en el cron para no tener que estar proporcionando la contraseña de SSH cada vez que nos conectamos.

¡Suerte!

Una posible solución al «No service» de los teléfonos Aastra (y como mejorar el rendimiento de los reportes de llamadas)

17 Jun

Para los que nunca han hecho uso de, Aastra es una marca de telefonía con base en Ontario, Canadá. Últimamente, su crecimiento se ha dado fuertemente gracias a la prevalencia de sistemas como Elastix que se integran muy bien con sus teléfonos. Mi percepción personal de la marca desde el punto de vista del valor del producto es intermedio: no es una marca tan barata como Grandstream o Yealink, pero tampoco es una tan cara como Polycom o Cisco. Es una marca que está a muy buenos medios términos en cuanto a calidad y funcionalidades se refiere.

Un «inconveniente» que tienen sus teléfonos es que son extremadamente sensibles al retraso de paquetes cuando están en modo de stand by. Esto quiere decir que constantemente los teléfonos están enviando paquetes a Asterisk para medir el estado del servicio, y si el servidor por un momento se retrasa con la respuesta, inevitablemente veremos el mensaje de «No service» en la pantalla de los teléfonos, que es como si no estuviéramos registrados.

La solución no siempre está bien establecida porque tenemos que encontrar (y solucionar) lo que sea que esté causando este retraso. Puede ser un problema de la red (no es muy común, pero puede ser) o puede ser que el servidor de Asterisk se encuentre en un proceso que consuma muchos procesos/CPU y ocasione que se retrase para emitir una respuesta. En este caso, vamos a analizar una posible cause de este segundo escenario.

El cliente que hoy me ha reportado que sus teléfonos están perdiendo el registro frecuentemente es una agencia automotriz, que tiene alrededor de unos 140 teléfonos conectados entre Linksys 921 y diversos modelos de la serie Aastra 675x (aunque el problema solo es con los Aastra, por la razón arriba mencionada).

Indagando un poco más, observe que de pronto sus procesos de MySQL subían alredor del 80% del CPU por unos segundos y luego, bajaban a 0%. Esto quiere decir que algo se come el procesador por un instante y luego lo suelta, pudiendo ser la causa del problema que tenemos. Indagué un poco más y me doy cuenta que por default Elastix no utiliza índices en las tablas de CDR, lo cual hace que todos los reportes del detalle de llamadas tengan que «barrer» todos los registros de la tabla para encontrar los que necesitamos. Para un PBX pequeño no hay mucho problema, pero para una tabla que tiene 3.6 millones de registros, buscar en todos ellos resulta algo de uso intensivo de CPU. Para corroborar mi teoria, activé el log de consultas lentas de MySQL, y al hacer un mysqldumpslow desde el Linux CLI, obtuve lo siguiente (no se fijen en el query, fíjense en el tiempo total para ejecutarlo):

[codesyntax lang=»bash»]

[root@100 asterisk]# mysqldumpslow -t 5 /var/log/mysql/mysql-slow.log

Reading mysql slow query log from /var/log/mysql/mysql-slow.log
Count: 14  Time=40.50s (567s)  Lock=0.00s (0s)  Rows=58.6 (820), asteriskuser[asteriskuser]@[XXX.XXX.XXX.XXX]
  SELECT  * from (SELECT  billsec as billsec ,calldate as calldate,clid as clid,src as src,dst as dst,dcontext as dcontext,channel as channel,dstchannel as dstchannel,lastapp as lastapp,lastdataas lastdata,duration as duration,disposition as disposition,amaflags as amaflags,accountcode as accountcode,uniqueid as uniqueid,userfield as userfield, calldate + INTERVAL duration SECOND as fecha_termino from cdr where calldate >= 'S') as resultado where fecha_termino >='S'order by calldate limit N, N

[/codesyntax]

Como se observa, cada consulta toma 40 segundos. ¡Esto es un mar de tiempo solo para ver las llamadas que ha hecho una extensión el día de hoy! El problema se confirma con un EXPLAIN del mismo query:

[codesyntax lang=»sql»]

mysql> EXPLAIN SELECT  * FROM ( SELECT  billsec AS billsec ,calldate AS calldate,clid AS clid,src AS src,dst AS dst,dcontext AS dcontext,channel  AS channel,dstchannel AS dstchannel,lastapp AS lastapp,lastdata AS lastdata,duration AS duration, disposition AS disposition,amaflags AS amaflags,accountcode AS accountcode,uniqueid AS uniqueid,userfield AS userfield,  calldate + INTERVAL duration SECOND AS fecha_termino FROM cdr  WHERE calldate >= ‘2011-01-01 00:00:01’)  AS resultado  WHERE fecha_termino >=’2011/06/17 16:44:23 ‘ORDER BY calldate LIMIT 0, 10000;

+----+-------------+------------+------+---------------+------+---------+------+---------+-----------------------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows    | Extra
                   |
+----+-------------+------------+------+---------------+------+---------+------+---------+-----------------------------+
|  1 | PRIMARY     |            | ALL  | NULL          | NULL | NULL    | NULL |  592484 | Using where; Using filesort |
|  2 | DERIVED     | cdr        | ALL  | NULL          | NULL | NULL    | NULL | 3617505 | Using where                 |
+----+-------------+------------+------+---------------+------+---------+------+---------+-----------------------------+
2 rows in set (27.90 sec)

[/codesyntax]

Allí se nota como la consulta NO usa índices y tiene que recorrer los 3.6M de registros. ¿La solución? Agregar un índice al campo calldate que es donde se hacen las consultas de manera principal. Esto se hace con el siquiente comando en MySQL (ojo: dependiendo del tamaño de la tabla de CDR este proceso puede demorar desde segundos hasta horas, por lo que planea muy bien que tu equipo esté disponible para ejecutar esta tarea)

[codesyntax lang=»sql»]

ALTER TABLE `asteriskcdrdb`.`cdr` ADD INDEX `calldate` (`calldate`);

[/codesyntax]

Y al terminar el proceso, podemos validar ejecutando el mismo EXPLAIN:

[codesyntax lang=»sql»]

+----+-------------+------------+-------+---------------+----------+---------+------+--------+-----------------------------+
| id | select_type | table      | type  | possible_keys | key      | key_len | ref  | rows   | Extra|
+----+-------------+------------+-------+---------------+----------+---------+------+--------+-----------------------------+
|  1 | PRIMARY     |            | ALL   | NULL          | NULL     | NULL    | NULL | 592516 | Using where; Using filesort |
|  2 | DERIVED     | cdr        | range | calldate      | calldate | 8       | NULL | 652745 | Using where                 |
+----+-------------+------------+-------+---------------+----------+---------+------+--------+-----------------------------+
2 rows in set (8.84 sec)

[/codesyntax]

Como se observa, la consulta ahora está reducida a 650K registros o bien un 82% de ahorro en cuanto al número de registros que se tienen que consultar.

Aunque esta puede bien no ser la única cause del problema, es un excelente primer paso. Ya ahorramos procesamiento en este ejercicio, ahora hay que indagar en que otros procesos del sistema podemos ahorrarnos unos ciclos para así dejar más recursos disponibles para nuestras llamadas.

Suerte,

Versión mejorada del mensaje «all circuits are busy» de Elastix (v3)

31 May

Este código se encuentra desactualizado. Hay una versión más reciente disponible en http://asteriskmx.com/2013/04/version-mejorada-del-mensaje-all-circuits-are-busy-de-elastix-v4/

En muchas ocasiones hemos oido el mensaje de «all circuits are busy» («todos los circuitos se encuentran ocupados» si es que tenemos los sonidos en Español) de Elastix. El problema con este mensaje es que es reproducido ante cualquier falla de nuestro enlace. Esto incluye a números que no existen, números desconectados y cualquier otra causa de error que no siempre es culpa de nuestro conmutador, pero que el usuario final siempre le achaca al sistema que le configuramos.

Con la intención de abrir un poco el panorama y dar más información sobre la causa del error, escribí este código para ayudar a distinguir cual es la verdadera causa del problema. Para ello, es necesario modificar 2 archivos, dentro de /etc/asterisk

// Archivo extensions.ael
macro outmessage(HC) {
        switch(${HC}) {
                case 1:         // Unnalocated or unnasigned number
                                // El numero que marco no existe
                        Set(MSG=no-existe);
                        break;
                case 17:        // User is busy
                                // Tono ocupado
                        Busy;
                        break;
                case 20:        // Subscriber absent
                                // El número celular que usted marcó no está disponible o se encuentra fuera del area
                        Set(MSG=numero-celular-no-disponible);
                        break;
                case 28:        // Address incomplete
                                // Numero mal marcado
                        Set(MSG=cannot-complete-as-dialed&check-number-dial-again);
                        break;
                case 27:        // Destination out of order
                case 38:        // Network out of order
                        // El telefono que marco esta fuera de servicio
                        // El telefono que marco esta descolgado o en reparacion
                        Set(MSG=fuera-servicio);
                        break;
                case 41:        // Temporary failure
                                // Falla temporal en la red
                        Set(MSG=falla-red);
                        break;
                case 42:        // Switching equipment congestion
                                // Congestion por alta cantidad de trafico en la central
                        Set(MSG=alto-trafico);
                        break;
                case 102:       // Recovery timer expired
                                // No se obtuvo una respuesta de la central telefónica
                        Set(MSG=no-respuesta);
                        break;
                case 34:        // Todos los circuitos están ocupados
                default:
                        Set(MSG=all-circuits-busy-now&pls-try-call-later);
        };
        Playback(${MSG},noanswer);
        &hangupcall();
};
; Archivo extensions_override_freepbx.conf
[macro-outisbusy]
exten => s,1,Progress
exten => s,n,Macro(outmessage,${HANGUPCAUSE})

Con estas modificaciones, necesitamos ejecutar dos comandos dentro del *CLI:

ael reload
extensions reload

Y por último, necesitamos extraer el contenido del siguiente archivo de sonidos dentro de la carpeta /var/lib/asterisk/sounds

Con esto, Elastix nos dará un poco más de información indicándonos los siguientes casos:

  1. El número no existe
  2. El número está fuera de servicio o en reparación

Para todos los demás problemas, se entregará el default de «todos los circuitos se encuentran ocupados»

Conforme consiga más grabaciones para diferentes casos, incluiré más códigos de error dentro de este código, a manera de poder diferenciar mejor cada error. Desde la siguiente liga pueden descargar los Sonidos para mejorar el mensaje de error de Elastix

La emoción de convertirse en dCAP

27 May

Habemos quienes nos dedicamos a Asterisk día y noche: es nuestro hobby, nuestro sustento, nuestra herramienta, en algunos casos hasta nuestra ideología. Quizá el hecho de tomar una certificación basada en lo que vemos va más allá del conocimiento y entra un poco en lo personal: creemos que eso nos define como profesionales, sentimos alguna decepción si acaso no la obtenemos. Ya no lo hacemos por decir que sabemos, lo hacemos por nosotros.

Hace poco más de 6 meses tomé la certificación como parte de sentir que tenía derechos para decir que sé (al final de cuentas, vivo de enseñar a otras personas y me sentiría muy mal conmigo mismo si no tuviera la garantía que no solo sé, sino que la máxima autoridad al respecto también opina lo mismo). En aquel día, con todo y 6 años dedicándome a Asterisk, llegué a presentar el examen con los típicos nervios:

¿Y si me preguntan justo lo que no estudié?
¿Y si todo este tiempo me enfoqué en las cosas equivocadas?
¿Y si creo que sé pero no sé?

3 horas después salí con un examen teórico contestado con buenas expectativas, y un examen práctico contestado hasta en los puntos extras (por si acaso). Tenía la incertidumbre de que yo creyera que me fue bien cuando no hubiera sido así. Afortunadamente, 1 semana después obtuve la buena noticia de que mi trámite de dCAP ya había comenzando y solo era cosa que me entregaran el certificado. Así me convertí en el dCAP #1917.

Hoy estoy del otro lado: soy el instructor del curso y estoy aplicando el examen a los asistentes. De hecho, estoy escribiendo este post mientras contestan el examen práctico. Sé lo que están sintiendo, sé lo que son los nervios de que el tiempo se acaba, quizá hasta el aroma de oficina que no es la tuya te intimida y cualquier cosa que sale mal te preocupa porque crees que no vas a acabar. Pero al final de cuentas, el conocimiento está dentro de uno, y una vez que logras hacer más allá la duda de si lo vas a lograr o no, es que te das cuenta de que realmente ya lo conseguiste.

Faltan unos minutos para que llegue el momento de evaluarlos. Mi deseo es que todos los que se han esforzado lo pasen, y aquellos que estén leyendo esto solo puedo decirles que pierdan el miedo. Nunca sabrán que tan fácil o complicado es hasta que no lo intentan.