Skip to main content.

16 Enero 2008

Hackeando ChanSpy

Hoy nos ha surgido la necesidad de grabar bajo demanda el audio procedente de un ChanSpy. Así entre las opciones por defecto no había nada que cumpliera nuestras necesidades. g_echelon.jpg

Como esta tarde teníamos el hacker_mode a ON, lo primero ha sido un vistazo rápido al app_chanspy.c, en el que nos hemos encontrado lo siguiente:

  1.  
  2. res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
  3.  
  4. ast_frfree(f);
  5.  
  6. if (!res)
  7.    continue;if (x == sizeof(inp))
  8.    x = 0;
  9.  
  10. if (res < 0) {
  11.   running = -1;
  12.   break;
  13. }
  14.  
  15. else if (res == ‘*’) {
  16.   running = 0;
  17.   break;
  18.   } else if (res == ‘#’) {
  19.        if (!ast_strlen_zero(inp)) {
  20.           running = atoi(inp);
  21.           break;
  22.        }
  23.  
  24.            ……………….

A la vista de esto, se nos ha ocurrido que si se pulsa una tecla como por ejemplo el 5, podríamos ejecutar lo que quisiéramos, desde escribir un valor en la DB de Asterisk, reproducir un fichero,… el límite es tu imaginación :)

Por poner unos ejemplos, a continuación se muestra cómo escribir en la DB el valor ‘uniqueid’ que se escribirá en el CDR y cómo reproducir un fichero:

  1.  
  2. if (res == ‘5′)
  3. {
  4.     ast_verbose(VERBOSE_PREFIX_3 "IRONTEC:Escribiendo en la DB el valor: %sn",csth.spy.chan->cdr->uniqueid);
  5.     if (ast_db_put("UNIQUEID", csth.spy.chan->cdr->uniqueid,"0") )
  6.         ast_verbose(VERBOSE_PREFIX_3 "IRONTEC: OK Database!");
  7.         else
  8.           ast_verbose(VERBOSE_PREFIX_3 "IRONTEC: ERR Database!");
  9.  
  10.         ast_verbose(VERBOSE_PREFIX_3 "IRONTEC:Escribiendo en la DB el valor: %sn",csth.spy.chan->cdr->uniqueid);
  11.         resultado = ast_streamfile(chan, "tt-monkeys", chan->language);
  12.  
  13.        if (!resultado)
  14.            res = ast_waitstream(chan, "");
  15.  
  16. }

Hasta aquí el hackeo de la tarde… Happy Asterisk hacking!!

Posteado por saul como Asterisk a las 8:05 PM CET

Sin comentarios »

Provisionamiento Linksys SPA9XX

Hace poco he necesitado hacer un poco de mass-deployment de teléfonos Linksys SPA922. La verdad es que son terminales que me gustan mucho. He probado los Thompson,los Grandstream y Snom de gama baja/media y la verdad es que para terminales comunes, no de operadora, me quedo con los Linksys: son bonitos y fiables.

El problema me llega cuando busco en Google ficheros de ejemplo sobre el provisionamiento de Linksys. No encuentro ningún ejemplo y tampoco explicaciones claras sobre cómo hacerlo. Bien, esto me pasa por no leerme completito el manual de administrador de los terminales donde en un párrafo se explica bien claro. El motivo de este post es que otro no pierda el tiempo que he perdido yo buscando en google algo tan sencillo.

Un fichero de provisionamiento de Linksys SPA9XX no es más que un fichero XML y es bastante sencillo de hacer. Voy a poner el ejemplo de un SPA922 pero es bastante generalizable a toda la gama.

Lo primero es saber que toda la configuración va en un fichero al que llamaremos spa922.cfg. El fichero admite todas las opciones que vemos normalmente en el interfaz web del terminal sin más que respetar algunas convenciones:

  • Los espacios en las opciones se sustituyen por guiones bajos
  • Las opciones asociadas a una línea han de llevar _X_ al final del nombre de la opción. X hace referncia al número de línea.
  • El fichero empieza y termina con las etiquetas <flat-profile></flat-profile>.

Pongo aquí un ejemplo de fichero. En realidad de dos porque las opciones comunes a todos los teléfonos se ponen en un único fichero y después las opciones particulares, tales como los datos de acceso, se ponen en ficheros individuales para cada teléfono. El genérico es el antes mencionado “spa922.cfg” y el particular es “spa922-${MAC}.cfg”

  1.  
  2. <flat-profile>
  3.  
  4.   <!– PROVISIONING –>
  5.   <resync_periodic>10</resync_periodic>
  6.   <resync_error_retry_delay>20</resync_error_retry_delay>
  7. <profile_rule>/spa922-MAC/spa922-$MA.cfg</profile_rule>
  8.  
  9.   <!– SYSTEM –>
  10.   <enable_web_server>yes</enable_web_server>
  11.   <enable_web_admin_access>yes</enable_web_admin_access>
  12.   <dhcp>yes</dhcp>
  13. <primary_ntp_server>10.10.10.1</primary_ntp_server>
  14.   <enable_vlan>no</enable_vlan>
  15.   <enable_cdp>no</enable_cdp>
  16.  
  17.   <!– SIP –>
  18.   <max_forward>70</max_forward>
  19.   <max_redirection>5</max_redirection>
  20.   <max_auth>2</max_auth>
  21.   <sip_user_agent_name>$VERSION</sip_user_agent_name>
  22.   <sip_reg_user_agent_name>$VERSION</sip_reg_user_agent_name>
  23. <dtmf_relay_mime_type>application/dtmf-relay</dtmf_relay_mime_type>
  24.   <use_compact_header>no</use_compact_header>
  25.   <rtp_port_min>8000</rtp_port_min>
  26.   <rtp_port_max>11000</rtp_port_max>
  27.   <symmetric_rtp>yes</symmetric_rtp>
  28.   <stun_enable>no</stun_enable>
  29.  
  30.   <!– REGIONAL –>
  31.   <time_zone>GMT+01:00</time_zone>
  32.  
  33.   <!– PHONE –>
  34.   <voice_mail_number>451</voice_mail_number>
  35.   <text_logo>Irontec%0ai::voz</text_logo>
  36.   <extension_1_>1</extension_1_>
  37.   <share_call_appearance_1_>private</share_call_appearance_1_>
  38.  
  39.   <!– EXT 1 –>
  40. <line_enable_1_>yes</line_enable_1_>
  41.   <subscription_expires_1_>3600</subscription_expires_1_>
  42.   <sip_port_1_>5060</sip_port_1_>
  43. <proxy_1_>10.10.10.1</proxy_1_>
  44.   <use_outbound_proxy_1_>no</use_outbound_proxy_1_>
  45.   <register_1_>yes</register_1_>
  46.   <make_call_without_reg_1_>no</make_call_without_reg_1_>
  47.   <register_expires_1_>3600</register_expires_1_>
  48.   <use_dns_srv_1_>no</use_dns_srv_1_>
  49.   <use_auth_id_1_>No</use_auth_id_1_>
  50. <preferred_codec_1_>G711a</preferred_codec_1_>
  51.   <use_pref_codec_only_1_>no</use_pref_codec_only_1_>
  52.   <g729a_enable_1_>yes</g729a_enable_1_>
  53.   <g723_enable_1_>no</g723_enable_1_>
  54.   <g726-16_enable_1_>no</g726-16_enable_1_>
  55.   <g726-24_enable_1_>no</g726-24_enable_1_>
  56.   <g726-32_enable_1_>no</g726-32_enable_1_>
  57.   <g726-40_enable_1_>no</g726-40_enable_1_>
  58. <dtmf_tx_method_1_>auto</dtmf_tx_method_1_>
  59.   <dial_plan_1_ ua="na">(1xxS0|2xxS0|6xxxxxxxxS0|9xxxxxxxxS0|xx.)</dial_plan_1_>
  60.   <enable_ip_dialing_1_ ua="na">No</enable_ip_dialing_1_>
  61.  
  62.   <!– User –>
  63.   <time_format>24hr</time_format>
  64.  
  65. </flat-profile>
  1. <flat-profile>
  2.  
  3.   <display_name_1_>Jon Bonilla</display_name_1_>
  4.   <user_id_1_>205</user_id_1_>
  5. <password_1_>secretillo</password_1_>
  6.  
  7. </flat-profile>

Una vez tenemos los dos ficheros, sólo necesitamos que el terminal sepa dónde encontrarlos. Hay varias maneras de hacerlo; la que he escogido es tener un servidor tftp en mi asterisk que sirva los ficheros al teléfono. Para ellos debemos instalar un servidor tftp. Para ellos como root instalamos atftp:
apt-get install atftpd
Editamos /etc/default/atftpd para decirle dónde estará nuestro directorio de tftp. En mi caso /tftpboot:
USE_INETD=true
OPTIONS="--daemon --port 69 --tftpd-timeout 300 --retry-timeout 5 --mcast-port 1758 --mcast-addr 239.239.239.0-255 --mcast-ttl 1 --maxthread 100 --verbose=5 /tftpboot"

Creamos el directorio /tftpboot y ponemos ahí el fichero general spa922.cfg. Después creamos el directorio “/tftpboot/spa922-MAC” donde irán los ficheros particulares de cada teléfono. Por ejemplo el “spa922-000e08de2995.cfg”

Ahora ya tenemos todo preparado. Sólo queda hacer saber al terminal dónde ha de buscar el servidor tftp. Para ello, lo que hacemos es pasarle una option desde el servidor dhcp cuando el terminal hace una petición. En el fichero de configuración del servidor dhcp /etc/dhcp3/dhcpd.conf tendríamos algo así:


subnet 10.10.10.0 netmask 255.255.255.0
{
range 10.10.10.100 10.10.10.254;
option domain-name-servers 212.55.8.132;
option routers 10.10.10.1;
option subnet-mask 255.255.255.0;
option broadcast-address 10.10.10.255;
option tftp-server-name "10.10.10.1";
}

Después de esto, tenemos que cuando enchufemos a la red el terminal nuevo éste cogerá la dirección de red del servidor, comprobará que hay un servidor tftp en el que encontrará sus ficheros de configuración y tendremos el terminal listo para usar sin haber tenido que tocar para nada el terminal o haber accedido a la configuración web. Esto es una gran ventaja en cuanto el número de terminales a implantar es mayor de unos pocos. Además si por alguna razón tenemos un usuario torpe y mete la pata, basta con reinicar el teléfono y éste se volvería a configurar con los valores correctos.

Para más parámetros a configurar en los terminales lo mejor es verlos todos detallados en el manual de linksys.

Posteado por Iker Sagasti Markina como Howto, Teléfonos IP a las 6:30 PM CET

2 comentarios »

15 Noviembre 2007

Reflexiones a la vuelta del SIMO

Esta ha sido nuestra primera edición en el SIMO como expositores, por lo que ahora que (casi) todo ha vuelto a la normalidad, toca reflexionar.

00027.jpg

Si miramos el SIMO en general, muchos dicen que el SIMO está de capa caída desde hace algunos años, y creo que no les falta razón, ya que cada vez se ve menos innovación… solo se ven móviles y televisores… No obstante, en nuestro campo, el de la VoIP, creo que va mejorando cada año y que concretamente éste, ha marcado un punto y aparte.

En lo que al público se refiere, hemos comprobado que ha sido bastante variado, pero la gran mayoría ya sabía “algo”, aunque fuera solo lo que querían. Si excluimos el sábado, que no acude público profesional, la afluencia de gente ha sido bastante regular y estamos muy satisfechos con las visitas recibidas.

Hablando del Día de la Comunidad, lo único que podemos decir es que fue excelente. Fue un placer poder conocer tanta gente de la comunidad, así como la posterior cena por cortesía de Avanzada7. Esto unido a las charlas diarias, ha dado una relevancia aún mayor a la comunidad de Asterisk y la VoIP en el panorama nacional.

Por último, comentar que la logística del evento fue exquisita por parte de Avanzada7, así como el trato recibido. Enhorabuena chicos! Nos vemos el año que viene!

Posteado por saul como Asterisk, General a las 8:37 PM CET

1 comentario »

3 Septiembre 2007

Fichaje en el departamento de Voz IP

SaghulNunca me han gustado los blogs. Ni leerlos ni mucho menos escribirlos. Siempre los he considerado un culto al ego. Hago algunas excepciones en el caso de los blogs técnicos donde se postean tutoriales y howtos que pueden ayudarte a aumentar tus conocimientos. Tales son los caso del blog de Julian Menendez, el de Elio Riojano y el de Iñaki Baz entre otros.

Voy a hacer una excepción en este caso para publicar una entrada no estrictamente técnica. Y es que Irontec ha hecho un “fichaje de verano” que creo merece la pena reseñar. Nada más y nada menos que Saúl Ibarra. Saúl es muy conocido en en las listas de correo de temática voz IP como las de Asterisk y Openser. Además tiene uno de esos pocos blogs que merecen la pena visitar. Podéis echarle un ojo aquí.

Sin duda un gran fichaje para nuestro departamento de voz IP. En fútbol a esto se le llamaría el fichaje del verano :-)

Posteado por Iker Sagasti Markina como Irontec, Personas a las 11:34 AM CEST

Sin comentarios »

30 Agosto 2007

Integración de Verbio en Asterisk II

VerbioEn uno de los últimos post de este blog hablábamos sobre la integración del motor de ASR y TTS Verbio en nuestra centralita Asterisk. La gente de Verbio y Avanzada7 han desarrollado nuevas aplicaciones para poder usar el motor de Verbio directamente desde el dialplan sin necesidad de usar AGI.

Estas aplicaciones están disponibles aquí. Además de las aplicaciones podemos encontrar una documentación muy clara sobre cómo instalar y cómo hacer pruebas, además de unos ejemplos. No voy a hacer un howto ya que todo esta perfectamente explicado en la documentación y sería redundante.

Llevo unos días probando esta nueva forma de usar verbio directamente desde el dialplan y por ahora tengo buenas vibraciones. Hay algunas diferencias sobre la forma antigua basada en AGI, la mayoría buenas:

  • La detección de silencio la hace Asterisk y no Verbio. Podemos configurar VAD para afinar aún mejor la detección.
  • Podemos lanzar simultáneamente un ASR y un TTS.
  • La opción bargein nos permite cancelar la locución durante un ASR cuando detectamos voz.
  • Tenemos la posibilidad de detectar tonos DTMF durante un ASR y dar así la opción al usuario de responder usando la voz o usando las teclas.
  • Tenemos opción de usar modo verbose para depurar la detección en cada canal. El demonio de verbio no ofrece debug cuando se ejecuta desde una consola. En este caso declara variables de control que nos permite controlar el flujo en el dialplan en caso de que haya errores.
  • El motor de verbio debe estar corriendo cuando se inicia Asterisk o éste dará error y no arrancará.

En general me parece un gran salto hacia delante en el reconocimiento de voz para los usuarios de Asterisk y apertura de mercado para Verbio. Buenas noticias para todos.

Posteado por Iker Sagasti Markina como ASR, Asterisk, TTS, Verbio a las 6:42 PM CEST

Sin comentarios »

Google Calendar en Asterisk

Hace no mucho comentábamos el uso de un calendario en webdav para que Asterisk comprobara los días festivos al recibir una llamada y supiera si debía permitir la llamada o saltar directamente al buzón de voz.

En esta entrada vamos a hacer algo parecido pero esta vez usando Google Calendar, el cual nos permite acceder a los eventos mediante una URL que apunta a nuestro calendario en formato Icalendar. Haremos que nuestro Asterisk consulte nuestro Google Calendar para tratar las llamadas entrantes y sepa si debe pasar la llamada, desviarla o saltar al buzón de voz del usuario.

Lo primero que haremos será crear una cuenta en google si no tenemos una. Con esta cuenta podemos crear tantos calendarios como queramos. En este caso crearemos un calendario para marcar los festivos de la empresa. Vamos a obviar los pasos a seguir para crear un calendario y supongamos que ya tenemos un calendario creado para tal efecto.

A la izquierda de la panatalla veremos nuestros calendario entre todos los que tenemos asociados a nuestra cuenta y debajo de ellos un enlace administrar calendarios.

Lista de calendarios

Pinchamos en administrar calendario y en la pantalla que nos sale elegimos el calendario que hayamos creado para marcar los festivos. Ahora tenemos una pantalla en la que podemos editar las propiedades del calendario, compartirlo con otros usuarios…etc. En este caso lo que nos interesa es la sección llamada Dirección Privada.

Dirección Privada

Vemos tres iconos XML ICAL HTML que nos dan acceso a nuestro calendario en diferentes formatos. En este caso lo que nos interesa es el formato ICAL. Guardamos la dirección del enlace al que apunta el icono porque es lo que vamos a usar para leer el calendario.

Una vez creado el calendario solo nos queda marcarlo con diferentes festivos. Podemos simplemente poner Festivo o podemos discriminar más y diferenciar todo lo que queramos. En este howto vamos a diferenciar festivos locales, festivos nacionales y festivos de empresa. Lo que vamos a hacer es crear un evento el día en cuestión, a cualquier hora y de cualquier duración, en el que pongamos estas etiquetas:

festivos

Una vez tenemos el calendario llega el momento de usarlo. Vamos a crear un AGI en ruby que consulte nuestro calendario y devuelva a asterisk una variable SALTO que usaremos en el dialplan.

calendario.rb

  1. #!/usr/bin/ruby
  2. require ‘rubygems’
  3. require ‘icalendar’
  4. require ‘open-uri’
  5. include Icalendar
  6. URL="http://www.google.com/calendar/ical/xxxxxx%40irontec.com/private-XXXXXXXXXXXXXXXXXX/basic.ics"
  7. calendarios = Icalendar.parse(open(URL))
  8. calendario = calendarios[0]
  9. festivo=nil
  10. calendario.events.each do |evento|
  11. if evento.dtstart.yday == Date.today.yday
  12. festivo=evento.summary
  13. break
  14. end
  15. end
  16. #Festivos
  17. if festivo == nil
  18. salto = "laboral"
  19. elsif festivo == "Festivo Irontec"
  20. salto = "festivo-irontec"
  21. elsif festivo == "Festivo Nacional"
  22. salto = "festivo-nacional"
  23. elsif festivo == "Festivo Local"
  24. salto = "festivo-local"
  25. else
  26. salto = "laboral"
  27. end
  28. print("SET VARIABLE SALTO #{salto}")
  29. exit

Una vez hecho esto ya solo tenemos que hacer el tratamiento en el dialplan. Doy por supuesto que ya sabemos hacer esto así que voy a poner una líneas meramente descriptivas:

  1. [entrantes]
  2. exten => 944048182,1,AGI(calendario.rb)
  3. exten =>944048182,n,Goto(${SALTO},s,1)
  4. [laboral]
  5. exten =>  s,1,NoOp(Aqui tratamiento de día laboral)
  6. [festivo-nacional]
  7. exten => s,1,NoOp(Festivo nacional)

Una vez hecho esto ya solo nos queda probarlo para ver que todo esta correcto. Ya tenemos una centralita aún más inteligente que demuestra una vez más que Asterisk está a años luz de las centralitas tradicionales. ¡Bienvenidos a la telefonía del siglo XXI!

Nota -> Siento lo de la indentación y coloreado del código pero wordpress es un mal bicho. Voy a ver si le hago la pelota a uno de mis compañeros del departamento web para que me hackeen un poco el CSS :)

Posteado por Iker Sagasti Markina como AGI, Asterisk, Howto a las 1:44 PM CEST

5 comentarios »

23 Mayo 2007

Integración de Verbio en Asterisk

VerbioVerbio es un sistema de reconocimiento y síntesis de voz (ASR y TTS) independiente del locutor. Mediante un AGI podemos llamar a Verbio para así crear un IVR controlado mediante voz en vez de marcaciones.

Usando las diferentes gramáticas que nos ofrece Verbio o las creadas por nosotros mismos, podemos reconocer teléfonos, DNI, nombres y lo que se nos ocurra. Esto permite una interacción mucho más natural con nuestra centralita Asterisk que la típica marcación para navegar un menú.

Supondremos Verbio instalado y configurado ya en nuestro servidor por lo que no hablaremos de la configuración de Verbio. Eso sería material de otro artículo.

Un ejemplo sencillo: La centralita da un mensaje de bienvenida a una llamada entrante. Pide el nombre de Juan o de Pepe para transferir a la extensión adecuada o se disculpa y pide de nuevo el nombre si no ha entendido lo dicho.

DIALPLAN:

exten => 888,1,NoOp(Llamada entrante)
exten => 888,n,Playback(bienvenido_diga_nombre)
exten => 888,n,Goto(889,1)
exten => 889,1,AGI(ASR.agi|nombres.txt|ISOLATED|2|5000)
exten => 889,n,GotoIf($[$[${VASR_RESULT} != ERROR] & $[${VASR_SCORE}>${UMBRAL}]]?400,1:401,1)
;
;Si no hay error en el reconocimiento
;si juan vete a juan y si no vete a pepe
exten => 400,1,n,GotoIf($[${VASR_RESULT} = JUAN]?200,1:201,1)
;
;Si hay error en el reconocimiento disculpas y vuelve al ASR
exten => 401,1,Playback(no_he_entendido_repita)
exten => 401,n,Goto(889,1)
;
exten => 200,1,NoOp(Extension de Juan)
exten => 201,1,NoOp(Extension de Pepe)
;
;si queremos tts
exten => xxx,1,AGI(TTS.agi|es|laura|Hola mundo hoy es ${DIA_DE_LA SEMANA})

El ASR.agi es un script que recibe como parámetro el tipo de gramática así como el fichero de gramática que vamos a usar. De esta forma, podemos usar el mismo AGI para interpretar nombres, números…

Su funcionamiento es muy simple: Graba lo que el usuario ha dicho, ejecuta el cliente de verbio para ASR y devuelve el valor reconocido así como una puntuación que nos indica lo fiable que ha sido el reconocimiento. Estos valores son los que utilizamos en el dialplan para saltar a una u otra extensión.

ASR.agi:

  1. #!/usr/bin/perl
  2. use strict;
  3. #
  4. $|=1;
  5. #
  6. # Setup some variables
  7. my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
  8. #
  9. #
  10. #Recogemos las cosas que nos pasa asterisk
  11. while() {
  12. last unless length($_);
  13. if (/^agi_(w+):s+(.*)$/) {
  14. $AGI{$1} = $2;
  15. }
  16. }
  17. #
  18. #Ahora unas cuantas variables mas
  19. my $uid     = "$AGI{uniqueid}";
  20. my $ruid     = sprintf("%d", $uid);#%d signed int, %u unsigned int
  21. my $asr_cfg     = "es";
  22. my $lang     = "es";
  23. my $voc_file     = $ARGV[0];
  24. my $gram_type     = $ARGV[1];
  25. my $rectime     = $ARGV[3];
  26. my $vf2t_cmd    = "verbiof2t";
  27. my $result     = 0;
  28. my $basedir     = "/var/lib/asterisk/verbio";
  29. my $vf2tpath     = "/usr/bin";
  30. my $verbiowavedir = "audio";
  31. my $myrecpath     = "$basedir/$verbiowavedir";
  32. my $voc_path     = "$basedir/gram";
  33. my $myrecfile     = "verbio-rec-$ruid";
  34. my $codec     = "alaw";
  35. my $skip     = "0";
  36. my $silence     = $ARGV[3]
  37. my $offset     = "0";
  38. my $voxserver     = "127.0.0.1";
  39. #
  40. #
  41. #Vamos a grabar lo que se dice
  42. print STDERR "Empezamos a grabarn";
  43. print "RECORD FILE  $myrecpath/$myrecfile $codec $stoprec $rectime $offset $playbeep s=$silence n";
  44. my $result = <STDIN> ;
  45. #
  46. #
  47. # Creamos el comando de reconocimiento
  48. my $comando = "/usr/bin/verbiof2t -l $lang -g $voc_path/$voc_file -t $gram_type -f $myrecpath/$myrecfile.$codec -c $codec -d $ruid -s $voxserver -k $skip";
  49. #ahora ejecutamos el comando
  50. system($comando);
  51. my $result = <STDIN> ;
  52. #
  53. open VF2T, "$comando |" or die "Error en ejecucion del cliente verbio";
  54. my $data = ;
  55. my @datax = split(‘:_##_:’, $data);
  56. close VF2T;
  57. #
  58. my $exit_value=$? >>8;
  59. if( $exit_value != 1)
  60. {
  61. print "SET VARIABLE VASR_RESULT \"ERROR\"n";
  62. unlink($myrecpath."/".$myrecfile.".".$codec);
  63. }
  64. #
  65. #
  66. #Quitar espacios de las variables
  67. $datax[0] =~ s/ /_/g;
  68. $datax[1] =~ s/ /_/g;
  69. $datax[2] =~ s/ /_/g;
  70. #
  71. #Redondeo del score
  72. $datax[2] = sprintf("%d", $datax[2]);
  73. #
  74. #Seteamos las variables de asterisk
  75. print "SET VARIABLE VASR_INDEX $datax[0]n";
  76. print "SET VARIABLE VASR_RESULT $datax[1]n";
  77. print "SET VARIABLE VASR_SCORE $datax[2]n";
  78. #
  79. #
  80. print STDERR "ASR terminadon";
  81. #
  82. #borramos ficheros temporales y salimos
  83. unlink($myrecpath."/".$myrecfile.".".$codec);

Se puede ver que el script setea las variables VASR_RESULT con el resultado del ASR y VASR_SCORE con la puntuación obtenida. En el dialplan se comprueba que el resultado no sea ERROR y que la puntuación supere un cierto umbral de fiabilidad para que el ASR se considere correcto.

En este ejemplo hemos usado el tipo de gramática ISOLATED y un fichero de gramática nombres.txt. EL fichero de gramática es muy sencillo: Es un fichero de texto con las salidas del ASR asociadas a las entradas esperadas y separadas mediante un tabulador:

NOMBRES.TXT:

JUAN juan
PEPE pepe

Es importante observar, que sea cual sea la entrada del usuario, Verbio lo interpretará como una de las entradas esperadas y por lo tanto, aunque se diga patata, Verbio nos devolverá JUAN o PEPE. Naturalmente, la puntuación del reconocimiento será menor y podemos dar por inválido el reconocimiento en el dialplan al no haber superado ${UMBRAL}.
El valor de UMBRAL es algo que se ha de estimar después de hacer pruebas, pero un valor de 25-30 para una gramática ISOLATED de este ejemplo es una buena aproximación.
La parte del TTS es casi idéntica a la de ASR: Un script que genera un fichero de audio a partir del texto que se le pasa como parámetro y que lo reproduce.

TTS.agi:

  1. #!/usr/bin/perl
  2. use strict;
  3. #
  4. $|=1;
  5. my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
  6. #
  7. #
  8. #Recogemos las cosas que nos pasa asterisk
  9. while() {
  10. last unless length($_);
  11. if (/^agi_(w+):s+(.*)$/) {
  12. $AGI{$1} = $2;
  13. }
  14. }
  15. #
  16. #Ahora unas cuantas variables
  17. my $uid = "$AGI{uniqueid}";
  18. my $ruid = sprintf("%d", $uid);
  19. my $language     = $ARGV[0];
  20. my $speaker     = $ARGV[1];
  21. my $text    = $ARGV[2];
  22. my $textfile     = "verbio-tts-$ruid.txt";
  23. my $wavefile     = "verbio-tts-$ruid";
  24. my $result     = 0;
  25. my $basedir         = "/var/lib/asterisk/verbio";
  26. my $verbiowavedir     = "audio";
  27. my $verbiotextdir     = "text";
  28. my $text2filedir     = "/usr/bin";
  29. my $vt2f_cmd        = "verbiot2f";
  30. my $voxserver         = "127.0.0.1";
  31. my $codec         = "alaw";
  32. my $sounddir         = "$basedir/$verbiowavedir";
  33. my $textfiledir     = "$basedir/$verbiotextdir";
  34. #
  35. #
  36. # Vamos a crear un fichero de texto con los parametros que nos pasa el asr por medio de asterisk
  37. open(fileOUT, ">$textfiledir"."/$textfile");
  38. print fileOUT "$text";
  39. close(fileOUT);
  40. #
  41. #Generamos el fichero audio para poder reproducirlo
  42. my $comando = $text2filedir."/$vt2f_cmd -l $language -k $speaker -t $textfiledir/$textfile -f $sounddir/$wavefile -c $codec -d $ruid -s $voxserver";
  43. system($comando);
  44. #
  45. #
  46. my $filetoplay = $sounddir."/".$wavefile;
  47. print "STREAM FILE $filetoplay \"#\"n";
  48. #

Con esto ya tenemos una implementación sencilla de Verbio integrado en Asterisk. Hacer un menú personalizado, mejorar los TTS con el uso de variables y usar diferentes gramáticas es trivial a partir de este punto.

Para terminar con este post sólo queda comentar lo bueno y lo malo de mis primeras experiencias con Verbio y Asterisk.

LO BUENO:

  • Verbio es independiente del locutor y no requiere entrenamiento previo para reconocer voces en un ASR.
  • El reconocimiento tiene muy buen desempeño en ficheros de gramática pequeños.
  • El servicio técnico de Verbio ha sido sencillamente genial en cada llamada que le hemos hecho con dudas y problemas.
  • Desarrollado por empresa catalana, verbio ofrece gramáticas para castellano, euskera, gallego y catalán entre otras.

LO MALO:

  • Las gramáticas buit-in de Verbio no se han comportado tan bien como la ISOLATED. En concreto, la de telefonía, aunque reconoce muy bien el número dado, no devuelve un score fiable.
  • La documentación que viene con Verbio es insuficiente y anticuada.
  • Los paquetes debian que hemos usado eran rpm “alienizados”. Faltaba una librería que hubo que pedir al servicio técnico de Verbio.
  • Verbio no es software libre.

CONCLUSIONES

Por las pruebas que hemos hecho, se puede usar verbio para un IVR controlado por voz o para recoger datos de clientes que llamen para dejarlos (un concurso o una reserva de billetes por ejemplo) siempre y cuando haya una extensión con un operador humano que coja las llamadas fallidas.

Hemos comprobado que muy por encima del error técnico (fallos de reconocimiento o de la centralita) esta el error social: Mucha gente no se siente cómoda hablando con un operador artificial y no hace caso de las instrucciones, por muy sencillas que estas sean; esta gente ha de tener el recurso de poder acceder a un operador humano. Aún no se puede dejar todo en manos de la máquina.

ACTUALIZACIÓN: Ahora ya hay una forma de usar verbio directamente desde dialplan sin necesidad de usar AGIs. En este mismo blog se puede encontrar una entrada al respecto.

Posteado por Iker Sagasti Markina como AGI, ASR, Asterisk, TTS, Teléfonos IP, Verbio a las 1:13 PM CEST

3 comentarios »

13 Marzo 2007

Detección de Fax en canales mISDN

La detección de Fax en Asterisk, es realizada de forma nativa en canales ZAP, pero para canales mISDN, esto no es así, por lo cual nos tenemos que ayudar de otras aplicaciones como puede ser NV_FaxFDetect.

NV_FaxDetect escucha si lo que nos entra por nuestro canal mISDN es un Fax (lo permite también en canales SIP y IAX) permitiéndonos además de detectar si lo que entra es un fax, detectar marcado DTMF o detección de voz.

Leer el resto de la entrada »

Posteado por David como Asterisk a las 11:57 AM CET

4 comentarios »

7 Marzo 2007

Parche para APP_Rxfax : Consultar estado

SpanDSP es una librería para el Procesamiento Digital de Señales (DSP) que necesitaremos para poder transmitir/recibir Fax a través de asterisk. Junto con SpanDSP los autores facilitan dos aplicaciones para enviar fax y recibir fax en asterisk (rx_fax y tx_fax). A pesar de que puedes encontrar buenos manuales para hacerlas funcionar no siempre consigues los resultados esperados.

Y es que si consultamos la ayuda de txFax:

----------------------------------------
TxFAX(filename[|caller][|debug]): Send a given TIFF file to the channel as a FAX.
The “caller” option makes the application behave as a calling machine,
rather than the answering machine. The default behaviour is to behave as
an answering machine.
Uses LOCALSTATIONID to identify itself to the remote end.
LOCALHEADERINFO to generate a header line on each page.
Sets REMOTESTATIONID to the receiver CSID.
Returns -1 when the user hangs up, or if the file does not exist.
Returns 0 otherwise.
—————————————-
El retorno (0 y -1) es una practica común en el desarrollo de aplicaciones para c, pero no así en asterisk, donde es mas común devolver algún valor en una variable o saltar a una prioridad +101.

Por lo que se hace muy difícil consultar el estado del envío, si se ha enviado con éxito o no, ya que la manera de actuar de esta aplicación es la siguiente:

  • Si el fax llega bien entonces se continúa con el dialplan, pero no hay NINGUNA variable para advertir ese resultado.
  • Si el fax llega mal entonces se pasa directamente a la extensión Hangup del contexto, igualmente sin dejar un resultado en una variable.

Aplicando la siguiente linea a la aplicación se consigue modificar el comportamiento de esta:


static void phase_e_handler(t30_state_t *s, void *user_data, int result)
{
struct ast_channel *chan;
char far_ident[21]; chan = (struct ast_channel *) user_data;
if (result == T30_ERR_OK)
{
t30_get_far_ident(s, far_ident);
pbx_builtin_setvar_helper(chan, “REMOTESTATIONID”, far_ident); /******************* LINEA PARA MODIFICAR ******************************/
pbx_builtin_setvar_helper(chan, “RESULTADO”, “ENVIADO”); }
else
{
ast_log(LOG_DEBUG, “==============================================================================n”);
ast_log(LOG_DEBUG, “Fax send not successful - result (%d) %s.n”,result,t30_completion_code_to_str(result));
ast_log(LOG_DEBUG, “==============================================================================n”); /******************* LINEA PARA MODIFICAR ******************************/
pbx_builtin_setvar_helper(chan, “RESULTADO”, “ERROR”);
}
}
/*- End of function ——————————————————–*/

Gracias a esa función se puede dar un valor a una variable de canal, y como ocurre cuando el resultado es correcto se continúa con el dialplan.

Aqui dejamos el parche para que app_txfax devuelva una variable de estado. Su uso es muy facil:

# cd /usr/src/asterisk/apps

# patch app_txfax.c < app_txfax.patch

Posteado por David como Asterisk, Howto a las 10:24 AM CET

3 comentarios »

21 Febrero 2007

No pongas un Asterisk con el WiMax de Euskaltel

El escenario

Euskaltel

Euskaltel utiliza enlaces Wimax para ofrecer cobertura telefónica e Internet en lugares donde no llega con sus líneas. El funcionamiento básico sería el siguiente:

  • Euskaltel recibe una llamada telefónica a su cliente (al que provee con WiMax).
  • Euskaltel envía esa llamada mediante SIP y RTP vía WiMax hasta el router del cliente.
  • El router WiMax convierte la llamada a telefonía analógica a través de los 2 puertos FXS que dispone.
  • El cliente recibe la telefonía a través de un RJ11 clásico. Es decir, el procesado VoIP en el enlace WiMax es transparente para el cliente.

Llegados a ese punto tenemos dos líneas de teléfono analógicas “normales y corrientes” que podemos conectar a puertos FXO de nuestra tarjeta TDM400 en Asterisk. Pues no.

El problema

Es entonces cuando se evidencia el grave problema de la incorrecta detección de colgado y de llamadas establecidas:

Leer el resto de la entrada »

Posteado por Iñaki Baz Castillo como Asterisk, Protocolos, Proveedores a las 12:39 PM CET

4 comentarios »

« Entradas Anteriores  Siguientes Entradas »
2005 © Irontec S.L. :: Powered by Irontec & Wordpress
[ IRONTEC S.L. - C.I.F. B-95274890 ]
[ Ctra. Basurto-Kastrexana nº70 / Enpresaldea ]
[ 48002 - Bilbao - Bizkaia ]