Asterisk. Revisando Opciones de Text To Speech

Asterisk: Tenia programado escribir en dos partes, sobre ASR y ahora sobre TTS (serian las dos cara de la moneda)

Siguiendo con la linea de programacion con AGI, ahora se me ocurre la opcion de dotar de un servicio de Text To Speech a nuestro Asterisk, del nivel AT&T Natural Voices utilizando el mismo sistema que aplicamos con nuestro sistema ASR en el anterior mensaje (como es un servicio con un modelo ASP evidentemente no tendremos problemas de licencias siempre y cuando ese sistema permanezca en activo). Lo malo, claro esta, que si ese servicio se modifica (la URL por ejemplo), nos quedamos sin “negocio”. Por eso que es conveniente si el sistema lo utilizamos en produccion y somos capaces de rentabilizarlo, pasar a un sistema de TTS local en nuestro sistema.

Para mantenernos en una linea open source como Asterisk, tenemos la opcion de Festival, el problema es que es de muy baja calidad comparado a soluciones de pago o la que voy a proponer aqui, a traves del TTS de Google

Texto a Voz con Google TTS

Vamos manos a la obra partiendo de la base AGI voy a obviar que se hicieron todos los pasos del mensaje anterior para instalar lo necesario (php-curl, y php-agi lo mas importante), hacemos lo siguiente:

Primero vamos a descargar un sistema para convertir de MP3 a WAV.

# aptitude install lame

Vamos a crear un Script PHP en /var/lib/asterisk/agi-bin/ podemos llamarlo por ejemplo asterisk-tts.php:


#!/usr/bin/php -q
<?php
require_once('phpagi-2.20/phpagi.php');
$agi = new AGI();

# Necesitamos pasarle la Cadena de Texto desde el Asterisk, y la recogemos con esta variable.
$traduccion = $argv[1];

# Aqui descargamos el fichero Mp3 haciendo pensar a Google que somos un Navegador
shell_exec("wget --header='User-Agent:Mozilla/4.0' 'http://translate.google.com/translate_tts?tl=es&q=".$traduccion."' -O /var/lib/asterisk/sounds/google-tts.mp3");
# Y convertimos el fichero con "lame" a wav que es reconocible por Asterisk
shell_exec("lame -h --decode /var/lib/asterisk/sounds/google-tts.mp3 /var/lib/asterisk/sounds/google-tts.wav");
$retString = "Fin de la conversion";
$agi->verbose($retString);
?>

Finalmente creamos una extension en nuestro DialPlan de Asterisk para que haga esta “gestion”:


exten => 2000,1,Answer()
same => n,Set(TTSVAR = "Lo que queramos convertir")
same => n,AGI(asterisk-tts.php,${TTSVAR})
same => n,Playback(google-tts)
same => n,Hangup()

Y ya esta, recargamos el dialplan de Asterisk como siempre, y marcando la extension 2000 oiremos con una voz muy sensual: “Lo que queramos convertir” … o algo asi 🙂

Como veis la dificultad de implantacion es nula, y eso es lo que mas me ha gustado de AGI, que no hace falta estar creando aplicaciones en C-Arcaico y recompilando el Asterisk con la app_c_arcaico y podemos tener una funcionalidad semejante (aunque no nativa y para los mas sibaritas, con menos rendimiento en terminos de picosegundos). Lo que tampoco tengo muy claro es que Google este feliz que esten utilizando su TTS masivamente, aunque estoy seguro que ya habra por ahi algun Call-Center que lo este haciendo. Si tienen experiencia me gustaria que me lo comentaran.

Texto a Voz con Festival TTS

Ahora os voy a explicar como hacer lo mismo, pero con el sistema TTS Festival en local, que os comente antes, y asi podeis comparar que os gusta mas:

Festival TTS digamos que fue desarrollado por una universidad e incorporado nativamente en Asterisk, asi que eso simplifica bastante las cosas ya que existe una Aplicacion especifica para el tratamiento de Texto a Voz directamente para el dial Plan de Asterisk (el modulo app_festival.so). Primero tenemos que comprobar si lo tenemos preparado.

Desde el CLI> module show like festival

Si aparece algo asi como app_festival.so y “1 modules loaded”, entonces ya lo tenemos, sino, nos toca recompilar Asterisk y en la parte de make menuselect tenemos que seleccionar el app_festival antes de hacer el “make && make install”

Ahora vamos a instalar festival

#aptitude install festival

Y ahora necesitamos voces en Español para Asterisk. Yo vivo en Andalucia ahora mismo, asi que barriendo para casa tenemos las que usa la junta de andalucia en la forja de Guadalinex:
http://forja.guadalinex.org/frs/?group_id=21

Vamos a descargar las de Silvia, para comparar el grado de sensualidad con respecto a Isabel de Google, todo sea por motivar a nuestros clientes varones.

# wget http://forja.guadalinex.org/frs/download.php/154/festvox-sflpc16k_1.0-1_all.deb
#dpkg -i  festvox-sflpc16k_1.0-1_all.deb
Y borramos el fichero de configuracion de festival que crea automaticamente, para poder utilizar mejor, el generico de Festival.
#rm /etc/festival.scm

La voz queda automaticamente instalada en la ruta:
/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_sf_diphone

Ahora necesitamos modificar el archivo de configuracion de Festival por defecto ubicado en /usr/share/festival/festival.scm al final del fichero agregamos:


(set! voice_default 'voice_JuntaDeAndalucia_es_sf_diphone)
(define (tts_textasterisk string mode)
(let ((wholeutt (utt.synth (eval (list 'Utterance 'Text string)))))
(utt.wave.resample wholeutt 8000)
(utt.wave.rescale wholeutt 5)
(utt.send.wave.client wholeutt)))
(set! server_access_list '("localhost\\.localdomain" "localhost"))

Con esto, nos permitira por un lado utilizar la voz de Silvia y por otro lado arrancar el servidor Festival

Ahora necesitamos configurar el servidor Festival, bajamos los ficheros de desarrollo de festival
#aptitude install festival-dev

Y copiamos el fichero de autoarranque de festival a nuestro /etc/init.d para que arranque automaticamente el servidor cada vez que iniciemos nuestra maquina Asterisk:
#cp  /usr/share/doc/festival/examples/festival.init /etc/init.d/festival
#chmod +x /etc/init.d/festival

Antes de arrancar el servidor de Festival para Asterisk, necesitamos añadir una linea en /etc/default/festival:
RUN_FESTIVAL = yes

Y ahora si podemos arrancar el servidor Festival para Asterisk con exito:
/etc/init.d/festival start

Y para que arranque cada vez que iniciamos el sistema:
#ln -s /etc/init.d/festival /etc/rcS.d/S99festival

Ya esta todo casi listo, solo nos queda la parte mas facil, crear una extension en el DialPlan para ejectuar la aplicacion Festival
exten=> 3000,1,Answer()
same => n,Festival(Lo que queramos convertir)
same => n,Hangup()

Recargamos el dialplan de Asterisk como siempre y si marcamos la extension 3000, tendremos a Silvia dandonos el resultado.

Algunas cosas curiosas que he observado.
La version 1.0-1 de Guadalinex para Pedro parece que esta mal empaquetada. Instala sobre la version de Silvia (es_sf) en vez de (es_pa)
Se puede resolver de varias formas, una es, bajando las fuentes  (Archivos de desarrollo de la voz de Pedro) en el directorio correspondiente /usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone

Necesitamos desempaquetar tambien el .deb de Pedro con el comando “ar” (#ar x festvox-palpc16k_1.0-1_all.deb)
Y luego descomprimir data.tar.gz y a traves de la estructura de directorios llegar a …/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group
Cambiamos el nombre al fichero que hay y lo copiamos a un nuevo directorio group dentro de nuestro directorio de Pedro antes creado
#mkdir /usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group
#mv  sflpc16k.group /usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group/palpc16k.group
O lo ideal si a  alguien le interesa que arregle ese fichero deb, no voy a ser yo, porque no me gusta demasiado.

Si tuviera que elegir personalmente un fichero para Festival en Español para Asterisk, eligiria de hecho, el fichero por defecto de festvox en español (el_diphone) que es el que mejor se entiende para mi gusto, aunque es voz masculina asi que no podriamos comparar bien para este ejemplo.
Se puede descargar y configurar siguendo los mismos pasos que antes, pero en el idioma por defecto poner “voice_el_diphone”
# aptitude install festvox-ellpc11k

Ahora puestos a comparar entre Festival TTS y Google TTS, creo que no hay color, pero para gustos los colores. Espero vuestras experiencias en el mundo del TTS.

Asterisk @ 10000 Horas

Un AGI Legendario: Publicacion en Twitter mediante ASR

Para muchos, hoy es un dia de fiesta en España, pero para mi, es mi, es como el dia oficial de Asterisk, y me siento especialmente inspirado. Y aprovechando el momento estuve planteando alguna aplicacion curiosa que hacer con AGI.

Echando la mirada atras, durante el penultimo dia del Asterisk Advanced, tuvimos una breve introduccion al AGI (Asterisk Gateway Interface), y porque no decirlo, a mi me resulto de lo mas interesante del curso. Siempre habia sabido que existia tanto AMI como AGI pero hasta ese momento no me “atrevi” a profundizar, sea por desconocimiento, y por complejidad aparente.

De hecho, concretamente en ese mensaje del Dia 4 del curso, no publique nada acerca de estos interfaces de Asterisk, porque me resultaban lo suficientemente interesantes e importantes como para minimo dedicarle uno o varios mensajes a los mismos.

Y aqui va el primero. Durante el curso, la practica basicamente se trataba, de llamando a una extension, esta ejecutaba un script PHP a traves de AGI y se publicaba un tweet generico con cierta informacion en un usuario especifico para el curso (por interes todos van aqui: http://twitter.com/#!/agilabtest)

Realmente la practica lo daba todo bastante “masticado”, los scripts hechos, y exactamente lo que era necesario para que funcionara, y lo que habia que modificar en el DialPlan.

Pero ahora, aprovechando esta idea, se me ocurrio ir un paso mas alla y ademas de poder explicarlo todo un poco mas en detalle, ampliar la funcionalidad a algo muy interesante: Poder escribir un tweet en nuestro Twitter, llamando a traves de una extension, y diciendo lo que queremos escribir, con un sistema de Automatic Speech Recognition, ASR, o Reconocimiento de Voz Automatico, y lo mejor de todo, sin coste alguno (¿es posible?). Hoy me quede con la cita “Everything is possible, even impossible is: I’m possible y tambien aporto su granito.

En primer lugar vamos a “preparar” el sistema con algunos componentes basicos.

Por un lado necesitamos una libreria para poder trabajar con PHP a traves de AGI, llamada PHP-AGI. Es posible su descarga desde aqui:
http://phpagi.sourceforge.net/

Para este ejemplo yo recomiendo la version 2.2X puesto que si en un futuro saliera una version superior es posible que el script aqui realizado ya dejara de funcionar
La descargamos  http://sourceforge.net/projects/phpagi/files/phpagi/2.20/phpagi-2.20.tgz/download

Y descomprimimos aqui: /var/lib/asterisk/agi-bin/
#mv ./phpagi-2.20.tgz /var/lib/asteirsk/agi-bin/
#cd /var/lib/asteirsk/agi-bin/
#tar -xvf phpagi-2.20.tgz

Ahora por otro lado necesitamos un script en php escificamente creado para “operar” con Twitter,  (de hecho es generico, serviria incluso para desarrollar nuestras propias aplicaciones en php en relacion a Twitter).  Aqui hay varias librerias para Twitter: https://dev.twitter.com/docs/twitter-libraries#php .

Pero la que nos interesa para este caso es la siguiente: http://classes.verkoyen.eu/twitter_oauth

La descargamos:

#mkdir twitter-oauth
#cd twitter-ouath
#wget https://github.com/tijsverkoyen/TwitterOAuth/zipball/2.1.2 -O twitter-oauth.zip
#unzip twitter-oauth.zip
Nos crea un directorio con un nombre sacado de GitHub asi que entramos en ese directorio
# cd  <directorio-recien-creado>
# cp twitter.php ../../twitter.php

Asi ya tenemos el script este en nuestro directorio AGI-BIN

Estos scripts utilizan PHP-CURL, asi que, si no lo tenemos instalado es un buen momento para hacerlo:
#aptitude install php5-curl

Tambien nos va a hacer falta un conversor de WAV a FLAC para el Reconocimiento de Voz Automatico. En este caso, instalamos SOX si es que no lo tenemos ya.
#aptitude install sox

Antes de crear el script, necesitamos algo muy importante. Las claves del API de Twitter para el desarrollo de aplicaciones. De hecho necesitamos crear y autorizar una aplicacion en Twitter que va a ser con la que va a operar nuestro Script. Para ello entramos en:
https://dev.twitter.com/user/login?destination=home

Accedemos con nuestra cuenta de Twitter. Le damos a “Create an app”. Ponemos un nombre, una descripcion y una web, si no teneis web, pues poned http://www.10000horas.com para promocionarla !
Despues creamos la aplicacion. Ya en la aplicacion nos vamos a “Settings” y tenemos que picar la opcion: “Read, Write and Access direct messages”. Considerad que vamos a escribir directamente en nuestro tweeter por tanto es fundamental que este permiso este “activado”.

Finalmente necesitamos todas las claves para el script a continuacion y apuntarlas. Son las siguientes
1. Consumer key
2. Consumer secret
Abajo picamos en “Create my access Token” y apareceran dos claves mas:
3. Access token
4. Access token secret
Fijaros que abajo del todo ponga Access Level: Read, write, and direct messages, si pone otra cosa, teneis que fijar el tipo de acceso como comente antes, y volver a recrear las claves.

Y ahora nos toca crear dentro de AGI-BIN el script que vamos a ejecutar desde la Aplicacion AGI en el Dialplan

En este caso creamos un fichero llamamosle por ejemplo agitwitter.php, con el siguiente contenido (gran parte esta extraido del contenido del script ofrecido en las practicas del Asterisk Advanced, por eso hemos utilizado el script Twitter-Oauth de Tijs Verkonyen, en vez de cualquier otro, una cuestion de ahorro de tiempo).


#!/usr/bin/php -q

<?php

# Aqui cargamos el script twitter.php y el phpagi que descargamos antes.
require_once('twitter.php');
require_once('phpagi-2.20/phpagi.php');

# Creamos un nuevo objeto tipo AGI 
$agi = new AGI();
$agi->answer();

# Aqui ponemos las credeciales que obtuvimos antes, en el mismo orden
# Estas que aparecen aqui son las de un usuario que cree de pruebas http://twitter.com/#!/pruebasadvanced
$consumerKey = 'xIpIGMm3kP610xh1sJVDCA';
$consumerSecret = 'vBT8eufZInFTPt02tGZeNdrb7o3YFDspCmtknS48JxY';
$accessToken = '414849063-IUB9SgA2fVr6vgk6zpYoJWAxwolGmlyA8qw361Z8';
$accessTokenSecret = 'ofo0kZrUTIXWJ1tul8zazifrNEhc0qTabzqHBADctvA';

# Aqui viene lo mejor del mensaje. Con estas lineas conseguimos un reconocimiento automatico de voz gracias a un servicio que pocos conocen
# y que ofrece el equipo de Google gratuitamente (al menos hasta lo que yo se).
# Creditos por ofrecerme este descubrimiento a http://www.ardumania.es

# Primero convertimos el fichero que generamos desde Asterisk a formato FLAC (que es el que admite Google)
shell_exec("sox  /var/lib/asterisk/sounds/twitter.wav /var/lib/asterisk/sounds/twitter.flac");

# Despues lanzamos una peticion a Google para que nos convierta el fichero FLAC en texto, nos devuelve una cadena de texto formato JSON
$linea = shell_exec("wget --post-file /var/lib/asterisk/sounds/twitter.flac --header='Content-Type: audio/x-flac; rate=8000' -O - 'http://www.google.com/speech-api/v1/recognize?lang=es_ES'");

# Convertimos esa cadena JSON gracias a PHP en un objeto directamente
$obj = json_decode($linea);

# Y conociendo la estructura exacta de ese objeto (contiene mucha mas informacion interesante, como la "calidad" de la conversion), sacamos el texto ya convertido
$tweet = $obj->{"hypotheses"}[0]->{"utterance"};

# Ya en adelante simplemente lo que hacemos es utilizando las funciones del script Twitter-Oauth publicamos en Twitter nustro Tweet
try

{
$t = new Twitter($consumerKey, $consumerSecret);
$t->setOAuthToken($accessToken);
$t->setOAuthTokenSecret($accessTokenSecret);

$retArray = $t->statusesUpdate($tweet);
$retString = "SUCCESS: Tweet id " . $retArray['id_str'] . " posted at " . $retArray['created_at'];
}
catch(Exception $e)
{
$retString = "FAILURE: " . $e->getMessage();
}

# Para terminar reportamos a Asterisk el resultado (si tenemos activada la opcion verbose en nuestro CLI podremos ver el mensaje de exito si salio bien la cosa
$randNum = rand(1000, 9999);

$retString .= ". ID " . $randNum;
$agi->verbose($retString);
$agi->hangup();

?>

Ahora una vez que tenemos el script PHP listo, solo nos falta editar nuestro DialPlan para ejecutarlo. En este caso he creado una extension minima para que podamos obtener el resultado que estamos buscando

exten => 1000,1,Answer()
same => n,Record(twitter.wav)
same => n,AGI(agitwitter.php)
same => n,Hangup()

Recargamos nuestro dialplan (CLI> dialplan reload) y listo!

Un tema muy importante para que todo esto funcione y que creo que a estas alturas sobra decir: ES FUNDAMENTAL TENER ACCESO A INTERNET EN NUESTRA MAQUINA ASTERISK

Esa es la unica “contrapartida” de poder tener un ASR gratuito y de maxima calidad… creo que en muchos casos es asumible. En otro caso tendremos que plantearnos otras alternativas de reconocimiento de voz automatico como por ejemplo Verbio recomendado por Avanzada 7 o LumenVox recomendado por Digium (que son de pago y nada baratos), o buscarnos la vida con CMUSphinx que es OpenSource y no esta mal (aunque  de momento es muy inferior tanto al ASR de Google y a los dos de pago).

Ahora desde nuestro telefono solo nos queda hacer esa llamada de cortesia a  la extension 1000, suena el tono de hablar, decimos lo que queramos publicar en nuestro tweet (sobra decir que cuanto mas claro hablemos mejor, y si decimos palabra a palabra mejor aun para mejorar el reconocimiento, aunque el ASR de Google para mi gusto es el mejor del mundo y es capaz incluso de reconocer las frase hecha sin demasiada vocalizacion con un amplio numero de aciertos). Despues de hablar pulsamos la Almohadilla (#) para guardar el fichero de Voz (twitter.wav) y finalmente esperamos a que Asterisk haga el resto.

Entramos en nuestro Twitter… y voila! Nuestro mensaje recien escrito (si todo fue bien, sino, como comente, recomiendo activar en el fichero /etc/asterisk/logger.conf para CLI (console =>) la posibilidad de verbose, asi podemos ver los resultados que nos devuelve el script PHP y si hay error, lo que captura el “catch” del script PHP).

Esta vez que con un solo mensaje he matado dos pajaros de un tiro: explicacion de una implementacion de ASR en Asterisk y el funcionamiento de AGI utilizando PHP (que hay que reconocer que a dia de hoy desde que salio PHP5 es el lenguaje de programacion interpretado que mas me gusta, aunque todo esto tambien se podria haber realizado en otros como Ruby On Rails o Python, si os fijasteis en la pagina de scripts para Twitter habia para varios lenguajes).

Y como siempre, y una vez mas, que cualquier comentario sera ampliamente bienvenido! Espero que les sea de provecho.

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.