Asterisk TTS: Usar Loquendo con un AGIscript

El uso de un TTS en asterisk es algo casi imprescindible cuando vamos a realizar una aplicación que tome dato sde un sistema externo. Ya que es la forma de convertir esos datos a algo que el usuario pueda entender.

Loquendo tts es un producto comercial que tiene voces en multitud de idiomas, voces de una calidad bastante alta y que he usado en alguna instalaci'on con unos resultados muy buenos.

Existen otros metodos para conectar loquendo con asterisk, pero hoy me voy a centra en el mas sencillo, que es usar un AGIscript directamente en el dialplan de asterisk. Bueno, sencillo del todo no es, pero incluyo un programita en C llamado txt2audio que facilitará mucho la labor.

Instalar

Paso 1: Instalar Loquendo TTS siguiendo la sinstrucciones del paquete. (Habitualmente se instalará en: /opt/Loquendo/LTTS7/)

Paso 2: Installar Asterisk con soporte para AGI. Si usáis asterisk, me imagino que no habrá problemas con este paso. El soporte para AGI, es opción por defecto.

Paso 3: Instalar es soporte Asterisk::AGI en perl usando cpan:

Primero actualicemos CPAN


perl -MCPAN -e shell
cpan> install MD5
cpan> install CPAN
cpan> reload cpan


Y luego instalemos el módulo Asterisk::AGI


cpan> install Asterisk::AGI


Script AGI

Crearemos el script loquendo.agi con el código que muestro a continuación en el directorio por defecto para los scripts AGI . (Habitualmente en: /var/lib/asterisk/agi-bin/)


#!/usr/bin/perl

use Asterisk::AGI;
use File::Basename;
use Digest::MD5 qw(md5_hex);

$AGI = new Asterisk::AGI;

my %input = $AGI->ReadParse();
my ($text)=@ARGV;
my $hash = md5_hex($text);
my $voice= "Leonor";
my $sounddir = "/var/lib/asterisk/sounds/tts";
my $wavefile = "$sounddir/"."tts-$hash-$voice.sln";
my $loquendoDir= "/opt/Loquendo/LTTS7/bin/";

unless (-f $wavefile) {
open(fileOUT, ">$sounddir"."/say-text-$hash.txt");
print fileOUT "$text";
close(fileOUT);

my $execf=$loquendoDir."txt2audio $sounddir/say-text-$hash.txt $wavefile $voice";
system($execf);
unlink($sounddir."/say-text-$hash.txt");
}
$AGI->stream_file('tts/'.basename($wavefile,'.sln'));


Programa txt2audio

Nos resta crear el programita que pase de texto a audio usando el api de loquendo. En si no es muy difícil, y cualquiera puede hacerlo basándose en los ejemplos que vienen con Loquendo TTS.

Para empezar, crearemos el directorio /opt/Loquendo/LTTS7/samples/c/txt2audio e incluiremos en él los dos ficheros que adjunto a continuación.

txt2audio.c


#include <stdio.h>
#include "loqtts.h" /* Loquendo TTS include file */

int main(int argc, char *argv[]) {

ttsHandleType hSession, hReader; /* Reader handle */
ttsResultType r; /* Error code returned by TTS APIs */
const char* p = "Ludoviko";

if(argc == 4) {
p = argv[3];
} else if(argc !=3) {
fprintf(stderr, "Run '%s <textfile> <wavfile> [<voicename>] '\n", argv[0]);
return -1;
}

fprintf(stderr, "Using voice %s\n", p);

/* Initializes a LoquendoTTS Reader using the implicit session */
r = ttsNewSession(&hSession,"/opt/Loquendo/LTTS7/bin/default.session");
if (r != tts_OK) {
fprintf(stderr, "%s\n", ttsGetErrorMessage(r));
ttsDeleteSession(NULL); /* deallocates all tts resources */
return r;
}

r = ttsNewReader(&hReader, hSession);
if (r != tts_OK) {
fprintf(stderr, "%s\n", ttsGetErrorMessage(r));
ttsDeleteSession(NULL); /* deallocates all tts resources */
return r;
}

/* Sets the persona parameters using mother tongue and default style */
r = ttsLoadPersona(hReader, p, NULL, NULL);
if(r != tts_OK) {
fprintf(stderr, "%s\n", ttsGetErrorMessage(r));
ttsDeleteSession(NULL); /* deallocates all tts resources */
return r;
}

/* Sends samples directly to the audio board */
r = ttsSetAudio(hReader, "LTTS7AudioFile", argv[2], 8000, tts_LINEAR, tts_MONO, 0);
if(r != tts_OK) {
fprintf(stderr, "%s\n", ttsGetErrorMessage(r));
ttsDeleteSession(NULL); /* deallocates all tts resources */
return r;
}

/* Converts text to speech */
r = ttsRead( hReader, argv[1], ttsFALSE, ttsTRUE, NULL); /* ttsRead keeps control until the end */
if (r != tts_OK) {
fprintf(stderr, "%s\n", ttsGetErrorMessage(r));
}

ttsDeleteSession(NULL); /* deallocates all tts resources */
return 0;
}


makefile


CC = gcc
CFLAGS = -O -Wall
PROG_NAME = txt2audio

../../../bin/$(PROG_NAME): $(PROG_NAME).c
cd ../../../bin && $(CC) $(CFLAGS) -I ../include libLoqTTS7.so ../samples/c/$(PROG_NAME)/$^ -Wl,--rpath,. -o $(PROG_NAME)

clean :
rm -f ../../../bin/$(PROG_NAME)


Parece obvio, pero lo digo: hay que compliar.


cd /opt/Loquendo/LTTS7/samples/c/txt2audio
make


Usarlo en el dialplan

Fianlmente ya podemos usar nuestro flamante TTS en el dialplan:

AGI(loquendo, 'Hello world')


NOTAS

  1. txt2audio.c necesita ser parcheado si la instalación de loquendo se realiza en un lugar diferente del mostrado pro defecto /opt/... Se puede hacer de dos formas, o parcheando la línea 20 para establecer la ruta correcta, o establecer la variable a NULL y desde el sistema, exportar la variable de entorno LTTS7_DEFAULTSESSION ante sde usar el programa.

  2. El makefile necesita tababuladores antes de las líneas 6 y 9 o se producirá un error del tipo 'missing separator'

  3. Escribí este artículo originalmente en http://www.voip-info.org/wiki/view/Loquendo+TTS hace unos meses. Hoy lo pego aquí traducido al español.

El directorio de configuración de WebSphere, ese gran desconocido desde que existe la consola de administración.

El post de hoy consiste en las notas que he ido recopilando sobre como pelearse con el directorio de configuración del WebSphere Application Server.

La versión sobre la que se han hecho es la 5.1, pero no ha cambiado sustancialmente desde entonces.

Acceder a la configuración de WAS 51 sin consola

La configuración de WAS se guarda en el directorio config de la instalación.

La estructura de directorios es la siguiente:


$WASHOME/config
+-cells
+-pericoNetwork (nombre de la celda)
+-applications
| +-ArqB2BEAR_R.ear
| | +-deployments
| +-WPI.ear
| · +-deployments
+-nodes
+-perico (nombre del nodo)
+-servers
+-B2B
+-WPI


Comprobar si esta activada la seguridad a nivel de celda

En el fichero $WASHOME/config/cells/nombreCelda/security.xml buscar la definición de security:Security y en ella el atributo enabled=true o enabled=false


<security:security
useLocalSecurityServer="true"
useDomainQualifiedUserNames="false"
** enabled="false"
cacheTimeout="600"
issuePermissionWarning="true"
activeProtocol="BOTH"
enforceJava2Security="false"
activeAuthMechanism="SWAMAuthentication_1"
activeUserRegistry="LocalOSUserRegistry"
defaultSSLSettings="SSLConfig_1">


Recuperar una contraseña almacenada en un fichero de configuración

Ejecutando la siguiente línea, podemos averiguar una contraseña almacenada en un fichero de configuración, por ejemplo la de la BBDD almacenada en la definición de un DataSource.


cd /usr/WebSphere/AppServer51/lib
../java/bin/java -cp securityimpl.jar:iwsorb.jar \
com.ibm.ws.security.util.PasswordDecoder \
{xor}contraseñaencriptada==


Advertencias para administradores de WAS confiados

Como se puede ver, accediendo al sistema de archivos de la maquina, estamos permitiendo que se tenga acceso a demasiada configuración.
Es habitual ver instalaciones, sobre todo pruebas de desarrollo y entornos de integración de software, en las que se concede acceso al sistema operativo para parar y arrancar servidores, ver logs, etc...
No cuesta mucho instalar un webmin con enlaces para parar, arrancar y acceder al log de cada uno de los servidores, incluso para instalar aplicaciones. El sistema quedará mucho, mucho, mucho mas seguro.

Usar kanban en el desarrolo de software.

Quien haya leído alguna vez sobre lean mamagement seguro que conoce el "Toyota Production System" y la importancia que el kanban tiene para él.

El desarrollo de software que todos sufrimos en estos días es muy similar al sistema de producción "just in time" por lo que no es descabellado adoptar paradígmas que funcionan es otros entornos de producción.

Al igual que en una planta de coches el driver que dispara la producción es el equipo de ventas que hace un pedido, en los equipos de desarrollo de software en disparador son los requisitos, las peticiones de cambio, o los defectos detectados.

Condición “sine qua non” para una mínima organización de un equipo de desarrollo es que conozcamos cuál es el ciclo desarrollo que seguimos desde que recibimos un "requisito", hasta que el cliente dispone del software que lo implementa. Este flujo es comparable a la línea de producción de una fábrica tradicional.

Un sencillo ejemplo de un flujo de trabajo:

requisito >> análisis >> construcción >> calidad >> aceptación del cliente.

La idea es asignar a cada uno de estos requisitos un identificador: El "kanban". Para que en todo momento los equipos que se encargan de cada tarea sepan en qué están trabajando. Al mismo tiempo, permitirá al jefe de proyecto conocer cuál es el estado de cada requisito y calcular métricas sobre los diferentes procesos.

¿Como articular esto?: Podemos empezar por una sencilla hoja de excel. Aquí podmeos ver claramente el pool de Kanbans pendientes al final de la hoja.



La idea no es nueva, por ejemplo: los códigos de incidencia de un equipo que se dedique a arregar defectos pueden ser tomados como Kanban. Las herramientas lo soportan fácilmente, por ejemplo: Clear Case puede almacenarlo sin problemas en la actividad.
Simplemente trataba de adecuar los paradigmas del "lean management" tradicional al mundo del desarrollo.

Acceso a los certificados del DNI electrónico

Hoy voy a poner a vuestra disposición una sencilla aplicación J2SE que permite acceder a los certificados del DNI electrónico.

Esta basada en el trabajo de David Calavera en su blog "Think in code"

El paquete se puede descargar desde aquí. Se trata de un JAR, ejecutable que contiene el código fuente.

El ejemplo esta basado en J2SE 6. Aunque es fácilmente portable a J2SE 5 importando las librerías como se hace en el ejemplo Unix, por claridad lo he preferido dejar en 1.6.

Para ejecutar el ejemplo, ejecutaremos:
java -jar pruebasDNIe.jar
Explico brevemente cómo funciona:

1.- Se recoge el almacén de certificados del sistema. Esta es la parte que difiere entre los diferentes sistemas operativos:
keyStore = KeyStore.getInstance("KeychainStore", "Apple");
keyStore.load(null, null);
2.- Obtenemos un enumeration con los diferentes certificados. (El DNI contiene 2, uno para firma y otro para autenticación).
Enumeration enumeration = keyStore.aliases();
3.- En cada elemento, tenemos un alias que nos permite acceder a la ruta completa de certificación.
String alias = enumeration.nextElement().toString();
Certificate[] certs = keyStore.getCertificateChain( alias );
Espero que os sirva para vuestros proyectos. Quedo pendiente de publicar un applet para firmar documentos usando este método.