Asterisk 11.7.0: pre-dial handlers, hangup handlers y la calidad de las llamadas SIP

Retomando un viejo articulo donde presentaba una forma medio espartana de guardar los datos relacionados con la calidad de las llamadas SIP en una tabla de una base de datos, en este articulo veremos como mejorar esa “captura” en Asterisk 11.

Esta parte se ha presentado en los Webinar dedicados a la Calidad de las llamadas SIP y creo que con esto se complementa lo que vieron en las diapositivas.

Vamos con orden.

Los Pre-dial Handlers son subrutinas que podemos configurar en línea de un Dial y/o FollowMe. Estas subrutinas se ejecutan después de la creación de los canales pero antes de realizar la llamada; permiten utilizar la nueva pieza de dialplan para, por ejemplo, guardar/crear variables que utilizaremos a lo largo de la llamada o, como en nuestro caso, configurar los Hangup handlers.

Los Hangup Handlers son subrutinas que se asocian a un canal (llamante y/o llamado) y se ejecutan cuando el canal cuelga. La diferencia con la extensión h es que esta ultima se ejecuta siempre y exclusivamente para el canal que ha iniciado la llamada. De hecho esta era la limitación que no permitía guardar los datos de la calidad de la llamada para el llamado.

Para crear un pre-dial handler, la sintaxis es bastante sencilla:

B([[context^]exten^]priority[(arg1[^...][^argN])])

para el llamante

b([[context^]exten^]priority[(arg1[^...][^argN])])

para el llamado.

Un ejemplo:

[externas]

exten => _00.,1,NoOp(Prueba handlers)
same => n,Dial(SIP/proveedor/${EXTEN},,B(externas^llamante_handler^1)b(externas^llamado_handler^1))
same => n,Hangup

En este bloque definimos que para el llamante se ejecutará la parte de dialplan contenida en el contexto [externas], extensión llamante_handler, prioridad 1. Para el llamado, contexto [externas], extensión llamado_handler, prioridad 1.

En esa dos extensiones ponemos:

exten => llamante_handler,1,NoOp(Llamante_Handler)
same => n,Set(CHANNEL(hangup_handler_push)=llamante,s,1);
same => n,Return

exten => llamado_handler,1,NoOp(Llamado_Handler)
same => n,Set(CHANNEL(hangup_handler_push)=llamado,s,1);
same => n,Return

En el bloque del llamante asociamos al canal el hangup Handler llamante,s,1. Esto significa que cuando el llamante colgará se ejecutará la subrutina en el contexto [llamante], extensión s, prioridad 1.

En el bloque del llamado asociamos al canal el hangup Handler llamado,s,1. Esto significa que cuando el llamante colgará se ejecutará la subrutina en el contexto [llamado], extensión s, prioridad 1.

Ahora creamos los dos contextos:

[llamante]
exten => s,1,NoOp(${CHANNEL(rtpqos,audio,all)})
same => n,set(tlp=${CHANNEL(rtpqos,audio,txcount)})
same => n,set(llp=${CHANNEL(rtpqos,audio,txploss)})
same => n,set(porlp=$[{CHANNEL(rtpqos,audio,txploss)} / ${CHANNEL(rtpqos,audio,txcount)} * 100])
same => n,set(trp=${CHANNEL(rtpqos,audio,rxcount)})
same => n,set(rlp=${CHANNEL(rtpqos,audio,rxploss)})
same => n,set(porrp=$[{CHANNEL(rtpqos,audio,rxploss)} / ${CHANNEL(rtpqos,audio,rxcount)} * 100])
same => n,set(hangupcause=${HANGUPCAUSE})
same => n,set(UA=${CHANNEL(useragent)})
same => n,Set(ODBC_cdr3()=${STRFTIME(${EPOCH},,%y%m%d%H%M%S)},${tlp},${llp},${porlp},${trp},${rlp},${porrp},${hangupcause},${UA})
same => n,Return

[llamado]
exten => s,1,NoOp(${CHANNEL(rtpqos,audio,all)})
same => n,set(tlp=${CHANNEL(rtpqos,audio,txcount)})
same => n,set(llp=${CHANNEL(rtpqos,audio,txploss)})
same => n,set(porlp=$[{CHANNEL(rtpqos,audio,txploss)} / ${CHANNEL(rtpqos,audio,txcount)} * 100])
same => n,set(trp=${CHANNEL(rtpqos,audio,rxcount)})
same => n,set(rlp=${CHANNEL(rtpqos,audio,rxploss)})
same => n,set(porrp=$[{CHANNEL(rtpqos,audio,rxploss)} / ${CHANNEL(rtpqos,audio,rxcount)} * 100])
same => n,set(hangupcause=${HANGUPCAUSE})
same => n,set(UA=${CHANNEL(useragent)})
same => n,Set(ODBC_cdr3()=${STRFTIME(${EPOCH},,%y%m%d%H%M%S)},${tlp},${llp},${porlp},${trp},${rlp},${porrp},${hangupcause},${UA})
same => n,Return

Con los dos bloques asociamos a unas cuantas variables algunos datos relacionados con la llamada (paquetes enviados totales, paquetes enviados perdidos, un calculo del porcentaje de los paquetes enviados perdidos, paquetes recibidos totales, paquetes recibidos perdidos, un calculo del porcentaje de los paquetes recibidos perdidos, la causa del colgado y el el UserAgent del dispositivo utilizado para la llamada). En la penúltima línea de cada bloque guardamos estos datos en una tabla que tenemos que crear:

Si la base de datos donde guardamos los registros de las llamadas se llama asteriskcdr:

mysql -u root -p sesamo

mysql> use asteriskcdr;

mysql> CREATE TABLE `cdr3` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `calldate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `tlp` int(15) NOT NULL DEFAULT '0',
  `llp` int(15) NOT NULL DEFAULT '0',
  `porlp` decimal(6,3) unsigned zerofill NOT NULL DEFAULT '000.000',
  `trp` int(15) NOT NULL DEFAULT '0',
  `rlp` int(15) NOT NULL DEFAULT '0',
  `porrp` decimal(6,3) unsigned zerofill NOT NULL DEFAULT '000.000',
  `hangupcause` varchar(80) NOT NULL DEFAULT '',
  `UA` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

mysql> quit

Si no la tenemos, creamos una conexión ODBC a la base de datos (para 64bit):

mv /etc/odbcinst.ini /etc/odbcinst.old

nano /etc/odbcinst.ini

[MySQL]
Description = ODBC for MySQL
Driver = /usr/lib64/libmyodbc5.so
Setup = /usr/lib64/libodbcmyS.so
FileUsage = 1

nano /etc/odbc.ini

[cdr]
Description = MySQL Asterisk-CDR2
Driver = MySQL
Database = asteriskcdr
Server = localhost
User = asterisk
Password = sesamo
Port = 3306
Option = 3

Cambien sesamo con la contraseña del usuario asterisk configurada en su MySQL. Guardamos los cambios y la probamos:

isql cdr asterisk sesamo

+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> quit

Luego modificamos este archivo:

nano /etc/asterisk/res_odbc.conf

y al final añadimos:

[cdr3]
enabled => yes
dsn => cdr
username => asterisk
password => sesamo
pre-connect => yes
sanitysql => select 1
idlecheck => 3600
share_connections => yes
;limit => 5
;forcecommit => no
;isolation => repeatable_read
;backslash_is_escape => yes
connect_timeout => 10

en dsn => ponemos el nombre de la etiqueta que da inicio al bloque configurado en el archivo odbc.ini. Guardamos los cambios.

Por ultimo modificamos el archivo func_odbc.conf que nos permite conectarnos a la base de datos y guardar los datos de las llamadas:

nano /etc/asterisk/func_odbc

al final del archivo copiamos:

[cdr3]
dsn=cdr3
writesql=insert into cdr3 (calldate,tlp,llp,porlp,trp,rlp,porrp,hangupcause,UA) values ("${SQL_ESC(${VAL1})}","${SQL_ESC(${VAL2})}","${SQL_ESC(${VAL3})}","${SQL_ESC(${VAL4})}","${SQL_ESC(${VAL5})}","${SQL_ESC(${VAL6})}","${SQL_ESC(${VAL7})}","${SQL_ESC(${VAL8})}","${SQL_ESC(${VAL9})}")

La línea que inicia con writesql= tiene que estar toda en el mismo renglón.

Guardamos los cambios y reiniciamos Asterisk:

service asterisk restart

Ya podemos realizar la primera llamada de prueba. Si no ven errores en la consola, deberían encontrar los datos en la tabla CDR3.

Me cuentan.

Vota el Articulo: 

Sin votos (todavía)
Evalúa la calidad del articulo
Suscribirse a Comentarios de "Asterisk 11.7.0: pre-dial handlers, hangup handlers y la calidad de las llamadas SIP" Suscribirse a VozToVoice - Todos los comentarios