Distribución uniforme del consumo de llamadas entre líneas (AGI-PHP)

27 Nov

Tarde o temprano nos vemos en la necesidad de considerar el gasto individual de las lineas telefónicas conectadas a nuestro Asterisk y encontrar una forma en que las llamadas se distribuyan de forma uniforme entre las lineas, no es lo mismo que 90% de la llamadas al exterior se realicen por la primera linea desocupada a que en caso de tener 4 se repartan en un 25% entre ellas.

Debido a esta necesidad me vi en la necesidad de crear un script en AGI PHP que junto con el dialplan nos haga este trabajo:

Para llevar el contador de las llamadas haremos uso de la asteriskdb, la base de datos integrada en asterisk. Lo que haremos es establecer primero las familias y las llaves que llevaran los datos, usando los siguientes comandos desde adentro del Asterisk CLI (*CLI):

asterisk -r

database put lineas 1 0
database put lineas 2 0
database put lineas 3 0
database put lineas 4 0

donde
lineas es la familia
1 la llave (que indicara el numero de la linea)
0 es el valor inicial del contador.

Se insertaran tantos registros como la cantidad de lineas que usaremos para la rotación de llamadas, de tal forma que quede como lo siguiente:

En nuestro dialplan (/etc/asterisk/extensions.conf) vamos a poner lo siguiente para que se haga uso del AGI que mas adelante revisaremos:

;----
En este caso usamos un prefijo 9 seguido de cualquier número conformado por 8 digitos (llamada local en México, Guadalajara y Monterrey), mandamos a ejecutar el AGI rotacion.php pasando como argumento el numero de telefono marcado sin el prefijo de marcación
-----;

exten => _9ZXXXXXXX,1,NoOp(${EXTEN})
exten => _9ZXXXXXXX,n,AGI(rotacion.php,${EXTEN:1})
exten => _9ZXXXXXXX,n,HangUp()

Ahora vamos a revisar el AGI:

#!/usr/bin/php
database_get("lineas",$i+1);
        $arrayLineas[$i]=$temporal["data"];
}
foreach ($arrayLineas as $key => $val) {
        //$agi->NoOp($key."---".$val);
        $agi->exec("Noop",$key."--->".$val);
}
asort($arrayLineas);
$agi->exec("Noop","despues de ordenar---------");
foreach ($arrayLineas as $key => $val) {
    //    $agi->NoOp($key."---".$val);
        $agi->exec("Noop",$key."--->".$val);
}
$agi->exec("Noop","Lista de los indices---------");
$arrayLlamadas=array();
foreach ($arrayLineas as $key => $val) {
        $arrayLlamadas[]=$key;
}
foreach ($arrayLlamadas as $key => $val) {
        $agi->exec("Noop",$key."--->".$val);
        $agi->NoOp($key."---".$val);
}
$contador=0;
$troncal=0;
$aux=0;
do {
        $troncal=$arrayLlamadas[$contador]+1;
        $agi->exec("ChanIsAvail DAHDI/".$troncal);
        $result = $agi->get_variable('AVAILCHAN');
        $agi->exec("NoOp","availchan:".$result["data"]);
        $contador++;
}while($result["data"]=="");
//$agi->NoOp("Numero de troncal:".$troncal);
//$agi->NoOp("Resultado final:".$result["data"]);
$aux=$agi->database_get("lineas",$troncal);
//$agi->NoOp("valor de aux:".$aux["result"]);
$agi->exec("Set","troncal=".(string)$troncal);
$agi->exec("Set","cantidad=".$aux["data"]);
$salida=$agi->exec_dial("DAHDI",(string)$troncal."/".(string)$numberGet);
?>

Luego, en nuestro contexto h para el manejo de llamadas (extensions.conf) ponemos lo siguiente:

; Las siguientes instrucciones son para fines de depuración (debug)
exten => h,1,NoOp("troncal "${troncal}) 
exten => h,n,NoOp(${DIALSTATUS})
exten => h,n,NoOp(${DIALEDTIME})
exten => h,n,NoOp(cantidad:${cantidad})

exten => h,n,Gotoif($["${troncal}" = ""]?internal,h,colgar) ; llamadas entre extensiones
exten => h,n,Gotoif($["${DIALSTATUS}" != "ANSWER"]?internal,h,colgar)

; Se revisa el tiempo que lleva la llamada (esto para lineas analogicas)
exten => h,n,Gotoif($[${DIALEDTIME} < 17]?internal,h,colgar) 
exten => h,n(suma),Set(DB(lineas/${troncal})=${MATH(${cantidad}+1)})
exten => h,n(colgar),HangUp()

Ahora, cuando se hacen llamadas internas entre extensiones el agi se ejecutara, pero la troncal va a estar vacia, capturamos esa condicion para simplemente colgar y no incrementar el contador de la troncal o linea.

Al detectar que troncal no esta vacia quiere decir que la llamada es hacia el exterior, por lo cual se revisamos el estatus de la llamada,
si el estatus es ANSWER quiere decir que la llamada fue aceptada (ojo, en México telmex no usa inversión de polaridad para marcar el estatus de llamada en lineas analogicas, por ese motivo tuve que usar una condicion de tiempo, tratando de abarcar un tiempo razonable que nos indique que la llamada fue tomada en realidad, en lineas digitales no se tiene este problema). Al final lo que hacer es incrementar el contador de la troncal que se utilizo y listo.

Este script no es perfecto pero me ha servido bastante bien, sientanse libres de mejorarlo, lo que pediria es citar la fuente original osea su servidor y compartir la mejora con la comunidad.

Creditos:
David Castañón Lara
Licencia tipo: Invitame una chela o si lo necesitas dame chamba (soy freelance), o en su defecto solo dame tu opinion
preack [arroba] hotmail.com
@the_preack

 

 

Christian Cabrera

Soy ingeniero en comunicaciones con especial interés en el área de voz sobre IP y tecnologías sobre información. He usado Asterisk de manera diaria desde hace más de 18 años. En el 2011 co-fundé Enlaza Comunicaciones, una empresa que se especializa en brindar servicios profesionales de consultoría sobre voz sobre IP basadas en Asterisk, así como servicios de interpretación simultánea y traducción.