PROYECTO FIN DE CARRERA INGENIERÍA INFORMÁTICA

Tamaño: px
Comenzar la demostración a partir de la página:

Download "PROYECTO FIN DE CARRERA INGENIERÍA INFORMÁTICA"

Transcripción

1 Facultad de Informática Departamento de Computación PROYECTO FIN DE CARRERA INGENIERÍA INFORMÁTICA Desarrollo de un Set Top Box basado en Linux para un servicio de vídeo bajo demanda Autor: Samuel Rivas González Tutor: Víctor M. Gulías Fernández A Coruña, 30 de Junio de 2003

2

3 Especificación Título del proyecto: Desarrollo de un Set Top Box basado en Linux para un servicio de vídeo bajo demanda Clase: Proyecto clásico de ingeniería. Nombre del alumno: Samuel Rivas González. Nombre director: Víctor M. Gulías Fernández. Nombre del tutor: Víctor M. Gulías Fernández. Miembros del tribunal: Miembros suplentes: Fecha de lectura: Calificación:

4

5 A mi abuelo Luís

6

7 Agradecimientos Supongo que será innecesario decir que no he sido yo el único artífice de que llegara el momento de escribir estas líneas; son tantas las personas a las que debo mucho por el apoyo y ayuda que he recibido durante todos estos años de carrera que sería imposible nombrarlas a todas sin adjuntar un nuevo tomo a este documento. Me gustaría, sin embargo, mencionar a algunas personas que han tenido una especial influencia en el hecho que que ahora mismo esté a punto de terminar este proyecto: A mis padres, por darme la oportunidad de llegar hasta el final de este carrera y el apoyo necesario para conseguirlo. A mis hermanos, mis abuelos y mis tías que me llevan aguantando tantos años. A Rubén y Julio, por las prácticas y los exámenes que preparamos juntos. A Pablo, por las horas de estudio que compartimos. A todos los que soportaron la convivencia conmigo: Iván durante 5 años y Xavi, Fernando y Julio (otra vez) durante este último año de carrera. A Víctor, por llevarme el proyecto. A la gente del laboratorio LFCIA por toda la ayuda que me ofrecieron durante este trabajo. Y a todos mis amigos que en algún momento de mi vida me han ayudado o sencillamente han compartido parte de su tiempo conmigo. Sin eso sería imposible haber llegado hasta aquí. Muchas gracias.

8

9 Resumen El objetivo de este proyecto es desarrollar un Set Top Box que permita al usuario final acceder a un servicio de vídeo bajo demanda a través de una interfaz definida en un servidor remoto. Las limitaciones de espacio a las que se debe atener el software desarrollado para realizar las funcionalidades requeridas en el Set Top Box obligan a la utilización de bibliotecas de bajo nivel para el control del hardware gráfico. Para ello se ha elegido la biblioteca DirectFB, que permite controlar directamente el dispositivo framebuffer de Linux a través de un API escrito en C, que será el lenguaje utilizado para implementar la aplicación encargada de comunicarse con el usuario. La interfaz presentada por el Set Top Box al usuario será definida utilizando el estándar XML. Para ello se ha desarrollado una aplicación que proporcionará los documentos XML necesarios a la aplicación cliente residente en el Set Top Box. Para el desarrollo de esta aplicación se ha elegido el lenguaje funcional Erlang. El software desarrollado para el Set Top Box deberá ser capaz de realizar las siguientes funciones: Comunicarse con el servidor de documentos XML utilizando el protocolo HTTP. Comprender los documentos XML recibidos y mostrar al usuario una interfaz de acuerdo con dichos documentos. Comprender eventos generados por el usuario a través de los periféricos de entrada pertinentes (por ejemplo, el mando a distancia). Realizar las acciones necesarias ante los eventos de entrada generados por el usuario; de acuerdo con las especificaciones de los documentos XML. Dichas acciones comprenden, entre otras, solicitud de nuevos documentos XML, reproducción de vídeo, cambios en las preferencias del usuario... La aplicación encargada de proporcionar los documentos XML se desarrollará de forma que realice las funciones mínimas necesarias para poder validar el correcto funcionamiento del software implementado para el Set Top Box. Esta aplicación recibirá peticiones HTTP y responderá enviando documentos XML utilizando el mismo protocolo. La información necesaria sobre los distintos usuarios y los medios disponibles se mantendrá en una base de datos.

10 Palabras clave DirectFB, framebuffer, Set Top Box, C, vídeo bajo demanda, XML, HTTP, Erlang, vídeo, interfaz.

11 Índice general 1. Introducción Introducción Objetivos Etapas del proyecto Estructura de la memoria Contextualización Vídeo bajo demanda Introducción Servidores de vídeo comerciales El servidor VoDKA Set Top Boxes Introducción Middleware Funcionalidades típicas Ejemplos comerciales Programación gráfica en Linux Introducción Framebuffer Microwindows Qt DirectFB Introducción Arquitectura Términos importantes API Análisis Introducción Protocolo de comunicación Set Top Box i

12 ii Índice general 3.4. Aplicación DFBCIn Introducción Módulo gráfico Parser Conclusiones Servidor XML (VXMLS) Ciclo de Desarrollo Introducción Prototipo DFBCIn VXMLS Prueba del sistema conjunto Diseño Introducción Definición de la interfaz y objetos del dominio Introducción La clase Menu La interfaz Action Documentos XML Introducción Descripción de los menús Protocolo de comunicación Diseño de DFBCIn División en subsistemas Interacción entre módulos Objetos comunes Diseño del motor de la aplicación Diseño del módulo VXMLS Diseño del módulo gráfico Diseño de VXMLS Introducción Objetos del dominio Modelo entidad-relación Diseño de la capa modelo Diseño de la vista y el controlador Implementación de DFBCIn Introducción Estándares de codificación Nombres

13 Índice general iii Objetos Control de errores Control de concurrencia Tipos de datos de uso general Pilas Arrays La clase Menu La clase Option La clase Key La interfaz Action Introducción Tipos de datos Funciones Cómo instanciar una acción? Cómo añadir una nueva acción? Implementación del motor de la aplicación Main Interface InterfaceInput Mp3Player Implementación del módulo VXMLS Módulo HTTP Parser VXMLS Parser para los documentos menu Implementación de la fachada VXMLS Implementación del Módulo gráfico Introducción Estructuración del código La fachada graphics.c La inicialización de DirectFB Control de eventos de entrada Impresión de menús y texto Reproducción de vídeo Módulo de pruebas Sistema de propiedades Etapas de codificación Desarrollo del núcleo de la aplicación Reproducción básica de vídeo Pruebas en el Set Top Box Varias mejoras Comunicación HTTP

14 iv Índice general Integración con VXMLS Integración con VoDKA Reproductor Mp3 y acciones de texto Implementación de VXMLS Introducción Generalidades sobre Erlang/OTP Cómo funciona Inets? Cómo funciona Mnesia? Servidores genéricos Estructura de la aplicación VXMLS Tipos de datos Control de errores Capa Modelo Tipos de datos Administración de la base de datos Funciones de la fachada Capa Vista Capa Controlador Generación de la respuesta HTTP Traducción de mensajes Fachada Creación y destrucción de sesiones Propiedades de personalización Generación de menús Composición de objetos Menu Menús definidos Ejemplos de vxmls get menu Extensibilidad Validación Despliegue del sistema Tamaño del software para el Set Top Box DFBCIn Problemas de rendimiento Problemas con avifile VXMLS Comportamiento general Problemas con Inets Streaming

15 Índice general v 8. Conclusiones y líneas futuras Conclusiones Continuación de este proyecto DFBCIn VXMLS A. DTD utilizados 193 A.1. DTD utilizado para la definición de menús A.2. DTD utilizado para la especificación de las respuestas de VXMLS 195 B. API del módulo gráfico de DFBCIn 197 C. Definición de IDirectFBVideoProvider 199 D. Tipos de datos en Erlang 203 E. Instalación y ejecución 205 E.1. Estructura de la distribución E.2. Instalación de VXMLS E.2.1. Compilación E.2.2. Instalación E.3. Instalación de DFBCIn E.3.1. Requisitos previos E.3.2. Compilación E.3.3. Ejecución F. Glosario 209 Bibliografía 213

16

17 Índice de figuras 1.1. Relación entre el usuario y el servidor de VoD Configuración interna de un Set Top Box Capas de un Set Top Box Prismiq MediaPlayer Set Top Box de HMMI XPC SS Acceso de una aplicación DirectFB al hardware gráfico Relación entre las interfaces de DirectFB Prototipo de interfaz con el usuario Creación de parsers con expat Aplicación DFBSee Aplicación DFBPoint Primera aproximación a la clase Menu Segunda aproximación a la clase Menu Diseño definitivo de la clase Menu Acciones para el manejo de menús Acciones para el control de vídeos Resto de acciones del sistema Módulos de DFBCIn Interacción entre los módulos de DFBCIn Clase Menu en DFBCIn Clases para el almacenamiento de datos Clases del motor Detección de eventos de entrada Ciclo de ejecución Estados de InterfaceInput e Interface Máquina de estados de Interface Interacción entre los componentes del módulo VXMLS vii

18 viii Índice de figuras Clases del módulo VXMLS Clases utilizadas para la construcción del parser para descripciones de menús Clases utilizadas para la construcción módulo gráfico Máquina de estados de VideoPlayer Aspecto visual de las dos implementaciones del módulo gráfico Patrón Model/View/Controller en el diseño de VXMLS Objetos del dominio Objetos valor utilizados para definir objetos Menu Objetos valor utilizados por VXMLS Modelo entidad-relación Clases de la vista y el controlador de VXMLS Despliegue del sistema final DFBCIn funcionando en el Set Top Box Capas de acceso al servicio de streaming Cluster servidor de vídeo utilizado

19 Capítulo 1 Introducción Índice General 1.1. Introducción Objetivos Etapas del proyecto Estructura de la memoria Introducción Un servicio de vídeo bajo demanda (VoD de aquí en adelante para simplificar) permite a los usuarios finales el acceso a medios de vídeo de forma interactiva sin ningún tipo de programación preestablecida. Para proporcionar este tipo de servicio es necesario un servidor de streaming que sea capaz de distribuir los medios en un flujo continuo de datos de forma que puedan ser reproducidos mientras se reciben. Para el usuario final, el servidor de streaming puede ser visto como un gran conjunto de medios sin estructura a los que puede acceder. Permitir el uso de esos recursos pasa por la obligación de desarrollar un sistema que posibilite el acceso de forma controlada a dichos medios y que los presente de forma comprensible y ordenada. Este es el objetivo que persigue este proyecto: desarrollar un Set Top Box que proporcione acceso desde el hogar a los medios distribuidos por un servidor VoD. 1

20 2 Capítulo 1. Introducción Para mantener centralizado el control de las interfaces presentadas a los usuarios, el software desarrollado seguirá el paradigma cliente-servidor, de forma que el software que controla el funcionamiento del Set Top Box obtendrá la información necesaria de un servidor, con el que se comunicará utilizando el estándar XML sobre el protocolo HTTP. Flujo Servidor VoD Actor Set Top Box n Servidor XML 1 Figura 1.1: Relación entre el usuario y el servidor de VoD El desarrollo de la aplicación cliente se ha realizado utilizando el lenguaje C y las bibliotecas DirectFB [1], para el control del hardware gráfico, y expat [2], para la implementación del parser XML. Esta aplicación recibe el nombre de DFBCIn (acrónimo de DirectFB Client Interface). El servidor XML se ha implementado utilizando el lenguaje funcional Erlang [3] y diversas herramientas proporcionadas por la plataforma de desarrollo Erlang/OTP [4]. Como servidor de VoD se utilizará VoDKA [5]. Por ello, a la aplicación encargada de servir los documentos XML se le ha bautizado como VXMLS (VoDKA XML Server) Objetivos El principal objetivo del proyecto es el diseño y desarrollo de un Set Top Box basado en Linux que permita el acceso de forma controlada al servidor de VoD VoDKA. El software desarrollado deberá ajustarse a las restricciones de espacio

21 Etapas del proyecto 3 presentadas por este tipo de sistemas. Como objetivo secundario también se desarrollará una aplicación que actúe como servidora de los documentos XML que necesitará el Set Top Box para generar la interfaz que presentará al usuario. Tanto el desarrollo del Set Top Box como de la aplicación encargada de proporcionar la descripción de la interfaz deberán cumplir los siguientes objetivos: Permitir al usuario acceder a los servicios de VoDKA a través de un televisor convencional. Controlar el acceso a los medios, manteniendo información sobre los usuarios que disfrutan de los mismos. Permitir a los usuarios elegir ciertas configuraciones para adaptar los servicios a sus necesidades. Por ejemplo, cada usuario debería poder elegir el idioma en el que se le proporcione la información que precise. Mantener la interfaz presentada a los usuarios siempre actualizada, pudiendo variar según, por ejemplo, la hora del día, las preferencias del usuario, etc Etapas del proyecto Durante el desarrollo del proyecto se ha pasado por las siguientes etapas: 1. Estudio de las diferentes alternativas existentes para programar accediendo directamente al dispositivo framebuffer de Linux. 2. Elección de una de las alternativas (en este caso DirectFB) e implementación de una aplicación de ejemplo para comprobar su idoneidad. 3. Elección de la estructura de los documentos XML que deberá interpretar la aplicación cliente. 4. Diseño e implementación de la aplicación cliente DFBCIn siguiendo el paradigma de desarrollo incremental. Como no se dispone todavía del servidor de documentos los incrementos iniciales trabajarán con documentos estáticos: en las primeras fases con ficheros y, una vez avanzado el desarrollo, solicitando los documentos de un directorio remoto utilizando el protocolo HTTP.

22 4 Capítulo 1. Introducción 5. Estudio de las herramientas proporcionadas por Erlang/OTP para el desarrollo de aplicaciones HTTP. 6. Diseño e implementación del servidor de documentos XML VXMLS. 7. Último incremento de la aplicación cliente, en el que se añadirá la funcionalidad necesaria para permitir la comunicación con el servidor implementado en el paso anterior. 8. Integración del sistema resultante con VoDKA. 9. Validación del sistema Estructura de la memoria En el capítulo 2 se expone una introducción a la tecnología de vídeo bajo demanda, en la que se hace una breve descripción del servidor VoDKA. También se exponen las características generales de los Set Top Boxes y de la programación gráfica bajo Linux, finalizando con un apartado dedicado a los aspectos generales de la biblioteca DirectFB. Los capítulos 3 y 4 describen las fases de análisis y diseño de este proyecto. La fase de implementación se divide dos capítulos: en el capítulo 5 se documenta la implementación del software diseñado para el Set Top Box y en el capítulo 6 se documenta la implementación del servidor de documentos XML. En el capítulo 7 se documenta la fase de validación del sistema. Por último, en el capítulo 8 se exponen las conclusiones obtenidas tras la finalización del proyecto y se exponen una serie de líneas de trabajo que quedan abiertas. Se incluyen varios apéndices con diversa información que puede ser de utilidad para comprender alguna de las secciones de esta memoria, información sobre la instalación y ejecución del software desarrollado y un glosario en el que se explican los acrónimos utilizados a lo largo de este documento.

23 Capítulo 2 Contextualización Índice General 2.1. Vídeo bajo demanda Introducción Servidores de vídeo comerciales El servidor VoDKA Set Top Boxes Introducción Middleware Funcionalidades típicas Ejemplos comerciales Programación gráfica en Linux Introducción Framebuffer Microwindows Qt DirectFB Introducción Arquitectura Términos importantes API

24 6 Capítulo 2. Contextualización 2.1. Vídeo bajo demanda Introducción La intención de un servicio de VoD es proporcionar un servicio de vídeo en el que múltiples usuarios pueden solicitar un objeto de vídeo en cualquier momento. Las posibles aplicaciones de un sistema de este tipo pueden ser: películas bajo demanda, noticias interactivas, aprendizaje a distancia, etc. Un sistema de este tipo debe incluir los siguientes elementos: El servidor de vídeo: Es similar a un servidor de ficheros normal, pero a diferencia de estos, debe priorizar el mantenimiento del flujo de datos constante. Un servicio de vídeo no puede proporcionar el vídeo completo ante una petición, puesto que el tamaño de los datos es demasiado grande. En lugar de esperar a recibir el vídeo completo, el terminal cliente recibe un flujo constante de datos, que irá reproduciendo a medida que le van llegando. Por lo tanto, el servidor de vídeo tiene que mantener el flujo de datos de manera ininterrumpida y con la cadencia adecuada para que la reproducción del vídeo en el terminal sea continua. Esta técnica se conoce como streaming. Para este proyecto se ha utilizado VoDKA como servidor de vídeo. El servidor de aplicaciones: Debe incluir dos módulos básicos: La aplicación de usuario: Garantiza la conectividad de los usuarios desde sus puestos remotos y le permite explorar entre los contenidos a los que está autorizado. Asimismo, esta aplicación también controla los datos y estadísticas de los distintos usuarios registrados. En el caso de este proyecto, se desarrollará la aplicación de usuario VXMLS. La aplicación de gestión: La aplicación de gestión de un sistema de vídeo bajo demanda incluye: alta, clasificación, modificación y borrado de los contenidos y los meta-datos; gestión y asignación de los perfiles de usuario; asignación de claves de acceso para los distintos niveles de contenido y monitorizado en tiempo real del estado del sistema. Los datos manejados por esta aplicación estarán en una base de datos a la que también accederá la aplicación de usuario. En [6] se ha desarrollado una aplicación de gestión para VoDKA que permite gestionar y administrar los usuarios y medios asociados al servidor VoDKA. Los codificadores en línea: Permiten ofrecer material no pregrabado. Deben ser capaces de obtener el vídeo y comprimirlo en tiempo real para proporcional material visual en directo.

25 Vídeo bajo demanda 7 Los terminales: En ellos es donde el usuario puede ver el vídeo que ha solicitado. Estos terminales pueden ser de dos tipos: ordenadores personales o Set Top Boxes (En este proyecto se desarrolla un terminal del segundo tipo). Los terminales reciben el vídeo, lo decodifican y lo presentan por pantalla al usuario. Normalmente, el software que controla el terminal también debe proporcionar la posibilidad de comunicarse con la aplicación de usuario. En este proyecto se desarrolla la aplicación DFBCIn para este propósito. La red: Deben tenerse en cuenta los factores de QoS, protocolos unicast y multicast y otros factores específicos para la transmisión de vídeo Servidores de vídeo comerciales En los últimos años las empresas más importantes que comercializan productos multimedia han desarrollado sistemas relacionados con el vídeo bajo demanda. Algunas de las soluciones están más adaptadas a redes de bajo ancho de banda, como es el caso de RealVideo Server, de Real Networks, que hacen uso de tecnologías de caché de los streams para optimizar el uso de una red con las características de Internet, o Microsoft Windows Media Server, que utiliza protocolos propietarios y puede ser utilizado en entornos de un mayor ancho de banda con un rendimiento menor. Otras soluciones se enfocan más a entornos LAN o WAN, con mayor disponibilidad de ancho de banda. Las más representativas son Darwing Streaming Server [7], de Apple, que es la versión de código abierto de Quicktime Streaming Server, y sólo es un servidor de streaming RTP, sin incluir la gestión del almacenamiento; DB2 Digital Library Video Charger [8], de IBM; Oracle Video Server [9, 10], quizá el más utilizado de todos, con arquitectura cliente-servidor, pero con limitaciones de escalabilidad; Kassenna MediaBase, una evolución de WebForce MediaBase, de SGI, con características comunes al diseño de VoDKA (modular, separación de funciones de adquisición, distribución y streaming, basado en sistemas UNIX), pero una menor flexibilidad y capacidad de adaptación; Philips WebCine Server [11], servidor de streaming MPEG4 basado en Linux; Cisco IP/TV [12], solución cerrada con herramientas orientadas al mercado de formación; y el sistema de SUN: StorEdge Media Central [13]. También existen soluciones de caja negra, que consisten en la combinación de un hardware especializado con alguno de los productos anteriores. En el contexto académico la mayoría de los proyectos poseen un carácter altamente experimental. En [14] se analiza una solución jerárquica para la construc-

26 8 Capítulo 2. Contextualización ción de servidores multimedia. En Stony Brook Video Server Project [15, 16, 17] se intenta crear un servidor distribuido que proporcione al usuario características de indexación, búsqueda y streaming de vídeos, y está desarrollada con una interesante arquitectura cliente servidor, adaptada para redes locales. En [18] se presenta una alternativa totalmente distinta a la expuesta en este artículo, utilizando una arquitectura de memoria compartida. Un estudio más detallado de algunas de estas soluciones se puede encontrar en [19] El servidor VoDKA Características generales de VoDKA El sistema VoDKA es un servidor de streaming multimedia bajo demanda extremadamente flexible, pero optimizado para el entorno de una operadora de telecomunicaciones. Características principales: Multiprotocolo: soporte para streaming de medios arbitrarios CBR por HTTP, MPEG-4 y Quicktime sobre RTSP/RTP, MPEG Layer3 (MP3) sobre RTP, MP3 sobre Icecast y ASF sobre HTTP con control del medio. Multiproveedor: previsión de múltiples proveedores de medios integrados en una única red de distribución de contenidos, cada uno en su dominio administrativo. Flexibilidad en el almacenamiento: posibilidad de utilizar almacenamiento en disco o cinta propio, servidores webdav [20] u otros servidores VoDKA encadenados como fuentes de medios. Modularidad: el sistema está compuesto de una serie de módulos que se interconectan de forma flexible para adaptarse a configuraciones muy diferentes. Distribuido: los distintos componentes del sistema se comunican entre sí de forma transparente a su localización. El servidor puede configurarse de forma adaptada a la topología de red, reduciendo costes de despliegue. Además, se modelan mediante funciones de coste las características de red y equipos para optimizar la utilización de enlaces y equilibrar la carga, asegurando calidad de servicio.

27 Set Top Boxes 9 Escalabilidad: gracias a su arquitectura, es posible configurar tanto un microservidor contenido en un equipo embebido como un cluster de cientos de nodos, e incluso metaclusters o agrupaciones de clusters Plataformas soportadas La mayor parte de VoDKA está desarrollada en Erlang/OTP (Open Telecom Platform). El código Erlang se ejecuta dentro de un runtime (ERTS), que incluye una máquina virtual (en la que se ejecuta o bien bytecode o bien código nativo), bibliotecas y una interfaz al sistema operativo y al hardware común a todas las plataformas. Todos los módulos desarrollados en Erlang, por tanto, pueden, en principio, instalarse sobre cualquier plataforma soportada por el ERTS: Solaris, AIX, BSD, VxWorks, Win32 y Linux sobre múltiples arquitecturas (x86, SPARC, ARM, PowerPC, S/390). Algunas partes de VoDKA están desarrolladas en C y C++, y puede que no estén disponibles para todas las arquitecturas Red de interconexión Cuando una instalación de VoDKA abarca más de un nodo físico, se supone que existe una red IP que interconecta todos los nodos entre sí. Es posible, sin embargo, dividir la red de nodos VoDKA en clusters independientes, pero complica el mantenimiento. En casos excepcionales es factible utilizar una red no IP, pero no es aconsejable en absoluto. VoDKA utiliza toda la infraestructura del sistema operativo para acceder a la red, con lo que podrá emplear cualquier interfaz soportado por éste. Habitualmente se desarrolla y prueba sobre interfaces Ethernet, Fast Ethernet y Gigabit Ethernet en Linux, y Fast Ethernet y ATM con LANE en Solaris Set Top Boxes Introducción Un Set Top Box puede ser visto como un dispositivo que permite realizar ciertas operaciones como el acceso a Internet o la recepción de vídeo digital desde el hogar, utilizando un televisor convencional como interfaz de salida y (posiblemente) un mando a distancia como dispositivo de entrada. En algunas ocasiones

28 10 Capítulo 2. Contextualización se denomina a los Set Top Boxes como decodificadores, o IRDs. Como ejemplos conocidos de Set Top Boxes se pueden citar los decodificadores de Canal+, Canal Satélite, Vía Digital, Quiero TV, etc. Internamente, un Set Top Box es similar a un ordenador personal convencional, pero con algunas modificaciones para adaptarlo específicamente a la ejecución de aplicaciones multimedia, como pueden ser decodificadores MPEG hardware, salidas de televisión digital, salida de audio estéreo, puerto de infrarrojos para el mando a distancia, etc. Como medios de almacenamiento secundario pueden disponer de un disco duro y/o memoria flash. También deben disponer de algún tipo de dispositivo de red para recibir la información multimedia, receptores de señal de televisión y un dispositivo de acceso condicional para controlar la utilización de los servicios de pago tales como el pago por visión. Puerto de infrafojos Codificador NTSC/PAL Decodificador de Control de pantalla y generacion de graficos DACs de audio video via satelite Decodificador de Logica de Control DACs de video video por cable Decodificador de Control de E/S CPU Memoria Modem video via terrestre Decodificador Distribucion de reloj MPEG RS232 xdsl Logica de Control Unidad de Acceso Condicional IEEE1394 Interfaz HDD Disco Duro/Flash USB Figura 2.1: Configuración interna de un Set Top Box Sobre la capa hardware se apilan las capas software necesarias para el correcto funcionamiento del Set Top Box, de forma similar a como se haría en un PC, como se puede ver en la figura Receptor de televisión digital: Dispositivos hardware necesarios para la recepción de la información necesaria. En la capa hardware también se con-

29 Set Top Boxes 11 Aplicaciones Capa de aplicacion API Middleware Plataforma Software Sistema Operativo de Tiempo Real Drivers Capa RTOS Receptor de television digital Capa Hardware Figura 2.2: Capas de un Set Top Box templan los dispositivos básicos para el funcionamiento del sistema (memoria, CPU, etc), pero se denomina receptor de televisión digital para señalar que no es una plataforma hardware genérica, sino que está orientada a esa tarea en particular. 2. Sistema Operativo: Se utilizan sistemas operativos de tiempo real (RTOS) como psos, WindowsCE, Linux, VxWorks, OS20 o Nucleus. 3. Plataforma software: También conocido como middleware. Conjunto de módulos que facilitan un desarrollo más eficiente. Proporciona un API para cada lenguaje de programación soportado. Para la implementación del API, el middleware puede incluir un gestor de aplicaciones, una máquina virtual, las bibliotecas, el motor interactivo y las bases de datos. 4. Aplicaciones: Esta capa no necesita estar residente permanentemente, sino que puede ser descargada bajo demanda. Un Set Top Box está pensado para ser una máquina asequible, que el usuario colocará en su hogar cerca del televisor para que realice las tareas necesarias que permitan el disfrute de un servicio de vídeo digital. Por lo tanto, es necesario aplicar ciertas restricciones sobre el hardware a utilizar.

30 12 Capítulo 2. Contextualización Debe ser razonablemente económico, esto implica que la CPU no tendrá toda la potencia de las últimas generaciones además de constreñir la cantidad de memoria RAM y la capacidad del dispositivo de almacenamiento secundario utilizado (disco duro o memoria flash). No debe ser voluminoso ni ruidoso. Esta restricción afecta a la utilización de discos duros y de chips o fuentes de alimentación que requieran dispositivos de ventilación para su correcta refrigeración. Para compensar las restricciones de potencia de la CPU, se suelen incluir decodificadores MPEG hardware para liberar a la CPU de la carga de esta tarea. Para disminuir los costes, ruidos y consumo, los Set Top Boxes no suelen incluir disco duro, sino que utilizan memoria flash como dispositivo de almacenamiento secundario. Además, es deseable que el bloque de memoria utilizado sea de la menor capacidad posible para no encarecer el sistema final Middleware En la actualidad existen varias organizaciones desarrolladoras de estándares para el desarrollo de plataformas middleware. DVB: El proyecto DVB [21] es un consorcio compuesto por alrededor de 300 operadores de vídeo, operadores de red, desarrolladores de software, fabricantes, etc. creado para el desarrollo de estándares para la transmisión de televisión digital y servicios de datos. De este proyecto han salido cuatro estándares mundialmente aceptados: DVB-S Estándar para la transmisión de vídeo digital vía satélite. DVB-T Estándar para la transmisión de vídeo digital por vía terrestre. Actualmente no está instaurado en América, en donde se utiliza ATSC, ni en Japón, en dónde se sigue el estándar ISDB-T. DVB-C Estándar para la transmisión de vídeo digital por cable. MHP Estándar de televisión digital interactiva. Define un interfaz genérico entre las aplicaciones interactivas y el terminal que las debe ejecutar. Un middleware que proporcione el interfaz MHP podrá ejecutar las aplicaciones desarrolladas de acuerdo con este estándar independientemente de la plataforma hardware que utilice. ATSC : Es una organización internacional sin ánimo de lucro para desarrollar estándares voluntarios para televisión digital. ATSC ha desarrollado

31 Set Top Boxes 13 numerosos estándares para transmisión de vídeo, codificación, compresión de audio digital, acceso condicional, etc. En cuanto a estándar de middleware ATSC ha propuesto el estándar DASE [22]. OpenCable: Es una iniciativa para dotar a la industria de televisión por cable de los estándares necesarios para desarrollar servicios interactivos. Como estándar de middleware propone OCAP [23]. JavaTV [24]: Especifica un API que proporciona una plataforma ideal de desarrollo y utilización de aplicaciones sobre la plataforma Java. Dicho API proporciona operaciones para realizar streaming tanto de audio como de vídeo, acceso condicional, control de canales y control de gráficos en pantalla. Algunas de las plataformas más utilizadas son: OpenTV [25]: Es la plataforma más utilizada en la actualidad para el desarrollo de sistemas de televisión digital sobre Set Top Boxes. Es una solución comercial ampliamente utilizada por compañías de televisión interactiva. Proporciona la plataforma middleware, aplicaciones, herramientas de desarrollo y soporte técnico. Las aplicaciones proporcionadas por OpenTV abarcan campos como el t-comercio, el streaming, telebanca, juegos, navegadores, etc. Es la tecnología utilizada por el Set Top Box de Vía Digital y QueroTV. Media Highway: Es un middleware propietario desarrollado por Canal+ Technologies [26]. Soporta los estándares DVB, OpenCable, y ATSC. Puede ejecutar aplicaciones interactivas escritas en lenguajes soportados por dichos estándares como Java, HTML o XDML. Es el middleware que utiliza el Set Top Box de Canal Satélite. Alticast [27]: Construye aplicaciones de televisión digital para una cantidad importante de proveedores en Asia. Su middleware soporta los estándares de aplicación MHP y DASE. Como máquina virtual en la que ejecutar las aplicaciones utiliza AltiJVM, que es una implementación de la máquina virtual de Java. TV Navigator: Desarrollado por Liberate [28], es un middleware con una representación importante en los Set Top Boxes de Estados Unidos. Soporta Java y HTML.

32 14 Capítulo 2. Contextualización MSTV [29]: Es el middleware desarrollado por Microsoft. Engloba varios productos como WebTV, PersonalTV y UltimateTV. Estos productos permitieron obtener a Microsoft el liderazgo en el mundo de la televisión interactiva, pero con el tiempo han ido perdiendo viabilidad comercial y están siendo abandonados. Ahora, Microsoft concentra sus esfuerzos en un middleware basado en su sistema operativo WindowsCE para compañías de cable. NDS Core [30]: Middleware desarrollado por NDS, principalmente instalado en Set Top Boxes de América Latina y Asia. Pretende ser compatible tanto con MHP como con OCAP y soporta Java y HTML Funcionalidades típicas Además de la recepción y reproducción de canales de audio y vídeo digital, los Set Top Boxes pueden realizar otro tipo de actividades como pueden ser la utilización de Internet, descarga de juegos, telecompra, telebanca, tienda virtual, solicitud de información de forma interactiva... Para los Set Top Boxes comerciales más conocidos en España, las funcionalidades van desde la más básica del Set Top Box de Canal+ hasta las más avanzadas ofrecidas por Canal Satélite y Vía Digital. El Set Top Box de Canal+ simplemente decodifica la señal recibida para permitir al abonado visualizar la programación que no se distribuye en abierto. Los Set Top Boxes de Canal Satélite y Vía Digital ofrecen servicios interactivos, además de proporcionar el acceso a los diferentes canales de vídeo. Algunas de las operaciones que permiten realizar son: Compra de estrenos o partidos. Consulta de información bursátil. Operaciones bancarias. Recarga de telefonía. Servicios de mensajes a móviles. Información deportiva. Guía de programación.

33 Set Top Boxes 15 Comercio por televisión (t-comercio). Teniendo en cuenta las posibilidades ofrecidas por un Set Top Box, se puede establecer la siguiente clasificación: Set Top Box para TV por broadcast: Es el nivel más básico de Set Top Box. No dispone de canal de retorno, simplemente recibe una señal de vídeo que decodifica para que el usuario pueda disfrutarla (por ejemplo, el decodificador de Canal+). Set Top Box para TV digital: Dispone de un canal de retorno para permitir la interacción del usuario con el proveedor del servicio de TV. Set Top Box avanzado: Tiene características muy similares a un PC: tienen una CPU potente, disco duro de gran capacidad, etc. Disponen de acceso de alta velocidad a Internet, posibilidad de grabación digital de vídeo, juegos, capacidad para el envío y recepción de correo electrónico, etc. Sidecar: Proporciona un nuevo canal de recepción de datos para trabajar conjuntamente con el canal recibido por el cliente en su Set Top Box original. Set Top Box híbrido: Set Top Box especializado para televisión por cable y que incluye otras funciones, por ejemplo, reproducción de DVDs Ejemplos comerciales Prismiq MediaPlayer Este Set Top Box obtiene medios audiovisuales de la red y los presenta de forma ordenada, permitiendo al usuario disfrutarlos en un televisor. Puede reproducir vídeo en formato MPEG 1 y 2 y DIVX con ayuda de un PC. La configuración de este Set Top Box es bastante simple, ya que el trabajo de localizar, adaptar y enviar los medios lo realiza una aplicación servidora que debe ser instalada en un PC: CPU : microprocesador NEC upd bit MIPS con un decodificador MPEG integrado. Memoria: 64 megabytes de SDRAM Interfaz de red: 10/100 Fast Ethernet integrada.

34 16 Capítulo 2. Contextualización Figura 2.3: Prismiq MediaPlayer Salidas de vídeo: S-Video y vídeo compuesto. Salidas de audio: S/P DIF y RCA (estéreo). Software: Linux 2.4, navegador y cliente AOL integrados Set Top Box de HMMI En este Set Top Box se hicieron algunas pruebas al principio del proyecto, pero el soporte de framebuffer para la tarjeta gráfica que tiene dio bastantes problemas y no se consiguió hacer funcionar correctamente la aplicación DFBCIn en él. Figura 2.4: Set Top Box de HMMI Shuttle Spacewalker XPC SS50 Este es el Set Top Box que se utilizó para la validación del sistema, se le instaló un receptor de infrarrojos para recibir la señal del mando a distancia y

35 Programación gráfica en Linux 17 un disco duro para facilitar las pruebas. La configuración original utiliza una memoria flash como almacenamiento secundario. Figura 2.5: XPC SS50 Las características de este Set Top Box son muy próximas a las de un PC: CPU : Intel Pentium 4 Socket478. Tarjeta de sonido: C-Media Electronics Inc CM8738 integrada. Tarjeta de vídeo: Silicon Integrated Systems SiS650/AGP VGA Display Adapter integrada. Memoria: 2 slots DIMM con capacidad de hasta 2 gigabytes de memoria DDR. Interfaz de red: 10/100 Fast Ethernet integrada. Salida de televisión/s-video. Slots de expansión AGP y PCI. Puertos USB y Firewire Programación gráfica en Linux Introducción Hoy en día, la programación de interfaces gráficas para Linux se hace habitualmente sobre el sistema X Windows que proporciona una capa de abstracción

36 18 Capítulo 2. Contextualización sobre el hardware gráfico y un API para desarrollar interfaces basadas en ventanas y eventos (tanto de teclado como de ratón). El sistema X Windows se ha transformado en el estándar de facto para la programación gráfica en Linux y Unix. X Windows permite el desarrollo de aplicaciones gráficas independientes del sistema operativo y la plataforma hardware, es transparente a la red y soporta numerosos entornos de escritorio muy populares hoy en día. Sin embargo, La utilización del sistema X Windows supondría una sobrecarga demasiado pesada para el Set Top Box. Como se dijo en la sección 2.2.1, un sistema de este tipo debe ser asequible y silencioso, lo que implica poco espacio en el almacenamiento secundario y una CPU de potencia limitada. Para aprovechar el hardware disponible será necesario utilizar algún framework de orientación menos genérica que X Windows. Por lo tanto será necesario buscar otras alternativas para la programación de la interfaz gráfica. La idea es bajar el nivel de programación y acceder directamente al hardware gráfico. Se utilizará un lenguaje de nivel medio-bajo para escribir directamente en el framebuffer (ver la sección 2.3.2). Sin embargo, trabajar directamente sobre el framebuffer es complicado y hace el código dependiente de la plataforma (si se quieren utilizar las posibilidades de aceleración gráfica). Por ello, se han estudiado distintos frameworks que proporcionen una mayor abstracción en forma de un API independiente del hardware gráfico. Las opciones estudiadas fueron: Microwindows [31]: Proporciona un API escrito en C que permite realizar operaciones gráficas básicas (rectángulos, círculos,...) y operaciones con ventanas. Está orientado a la implementación de aplicaciones gráficas con ventanas, pero prescindiendo de sistemas como Microsoft Windows o X Windows. Qt [32]: Proporciona un API C++ y una gran colección de objetos que permiten realizar aplicaciones con un look and feel nativo independiente de la plataforma. Para este proyecto se estudió su versión embebida (Qt/Embedded), que trabaja directamente sobre el framebuffer para evitar sobrecargas.

37 Programación gráfica en Linux 19 DirectFB [33]: Proporciona un API escrito en C, pero con diseño objetual. Está pensado para realizar operaciones gráficas con aceleración, evitando la utilización del sistema X Windows, en favor de la utilización del dispositivo framebuffer directamente [1]. Proporciona una abstracción de proveedor de imagen, de proveedor de fuentes y de proveedor de vídeo; Tiene operaciones para manejar la entrada ya sea por teclado, mando a distancia, ratón, joystick o pantalla táctil y define un sistema de gestor de ventanas. El framework elegido para la programación gráfica fue DirectFB, ya que proporciona muchas opciones interesantes para el desarrollo de software para un Set Top Box. Principalmente, la opción más útil es la abstracción que proporciona para el manejo de vídeo, que desacopla la aplicación del formato de vídeo utilizado Framebuffer El framebuffer es una parte de la memoria RAM de la computadora en la que se almacena la información para una imagen o frame. Esta información consiste típicamente en los valores de color para cada pixel de la pantalla. El kernel de Linux ha incorporado (a partir de su versión ) el dispositivo framebuffer [34], con el que permite la programación gráfica en una consola. Este dispositivo fue desarrollado con el objetivo inicial de permitir al kernel de Linux emular una consola de texto en sistemas como Apple Macintosh, que no soportan el modo texto VGA. Finalmente, el dispositivo framebuffer pasó a estar completamente integrado en el kernel de Linux y se espera que llegue a ser el modo estándar de acceso al hardware gráfico. El dispositivo framebuffer presenta una abstracción del hardware gráfico y permite a las aplicaciones software acceder al hardware gráfico utilizando una interfaz bien definida. De esta forma, el software no necesita conocer los detalles de bajo nivel (registros hardware), excepto para la aceleración hardware. La utilización del dispositivo framebuffer supone las siguientes ventajas: Proporciona un método unificado para el acceso al hardware gráfico a través de diferentes plataformas. Los controladores pueden ser compartidos entre distintas arquitecturas, lo que disminuye la duplicación de código.

38 20 Capítulo 2. Contextualización Proporciona control tanto para una como para varias pantallas activadas, se soportan hasta 8 dispositivos framebuffer (8 pantallas). El dispositivo framebuffer puede ser utilizado desde el espacio de usuario accediendo al dispositivo especial /dev/fb[0-7], de la misma forma que se accede al resto de dispositivos. E/S normal: Se puede acceder a los contenidos del framebuffer mediante las operaciones de lectura y escritura read() y write(). nmap: Utilizando la llamada nmap() se puede hacer mapping de los contenidos del framebuffer en la memoria de usuario, de forma que el framebuffer se vuelve una pieza de memoria accesible. También se puede hacer mapping de los registros MMIO en el espacio de usuario, pero para ello es necesario desactivar la aceleración hardware para la consola de texto para evitar conflictos en el acceso a dichos registros. ioclt: La llamada ioctl() permite realizar otro tipo de operaciones como cambiar el modo gráfico, obtener información sobre el hardware subyacente... Cada dispositivo framebuffer particular puede definir ioctls para operaciones especificas del dispositivo de ser necesario. No hay código genérico de aceleración gráfica en el kernel (solo para consola de texto), todas las operaciones genéricas de aceleración hardware deberán hacerse desde el espacio de usuario utilizando mapping sobre los registros MMIO Microwindows Microwindows [31] es un proyecto de Código Abierto que tiene como objetivo dotar las características de los sistemas de ventanas modernos a dispositivos y plataformas más pequeños. Permite desarrollar aplicaciones y probarlas en el escritorio de Linux para luego compilarlas para el dispositivo deseado. Proporciona dos APIs, uno compatible con el API del sistema de ventanas de los sistemas Win32/WinCE, llamado Microwindows, y otro similar al de Xlib, la biblioteca de desarrollo de aplicaciones para el sistema X Windows, llamado Nano-X. Bajo Linux es más utilizado el API Nano-X ya que soporta la arquitectura cliente-servidor. Actualmente funciona en sistemas Linux de 32 bits utilizando el soporte framebuffer del kernel (ver sección 2.3.2), bajo el sistema X Windows (útil para el

39 Programación gráfica en Linux 21 desarrollo) y utilizando la biblioteca SVGAlib 1. Adicionalmente, Microwindows ha sido portado para los sistemas operativos ELKS (Linux embebido de 16 bits), MS-DOS, tanto en modo protegido como en modo real, y RTEMS (sistema operativo de tiempo real). Las desventajas que presenta este framework con respecto a los objetivos que se persiguen en este proyecto son: Está orientado a la creación de interfaces con ventanas. La interfaz que se pretende desarrollar está basada en un sistema de menús a pantalla completa. El API proporcionado no es orientado a objetos, esto complicaría la estructuración del código, obligando a la implementación de una biblioteca propia para ocultar la utilización de este framework al resto del código de la aplicación. No proporciona operaciones de alto nivel como la reproducción de vídeo, aunque sí tiene operaciones para manipular imágenes y fuentes Qt Qt es un [32] framework para la creación de aplicaciones e interfaces gráficas multiplataforma. Incluye una biblioteca C++ y herramientas para facilitar el desarrollo rápido de aplicaciones. La biblioteca C++ proporciona una gran cantidad de clases completamente funcionales e interfaces consistentes. Está desarrollada totalmente siguiendo el paradigma de orientación a objetos. Las aplicaciones hechas con Qt se ejecutarán nativamente en las plataformas soportadas, las aplicaciones podrán ser portadas a nuevas plataformas simplemente recompilándolas con la biblioteca Qt correspondiente a la nueva plataforma. Este framework se distribuye para cuatro tipos de sistemas: Qt/Windows: Permite compilar las aplicaciones Qt para Microsoft Windows 95/98/Me, NT4, 2000 y XP. Qt/X11 : Para Linux, Solaris, HP-UX, IRIX, AIX y otras variantes de UNIX. 1 biblioteca que facilita el acceso a hardware de vídeo compatible con los estándares VGA y SVGA.

40 22 Capítulo 2. Contextualización Qt/Mac: Aplicaciones que funcionen sobre Apple Mac OS X. Qt/Embedded: Sistemas Linux embebidos utilizando el framebuffer en lugar del sistema X Windows como hace Qt/X11. La solución estudiada para el desarrollo del proyecto fue Qt/Embedded. Este framework no utiliza capas de emulación ni máquinas virtuales para posibilitar la portabilidad, cada edición es una implementación en código nativo del API ofrecido. La utilización de Qt ofrece las siguientes ventajas: Independencia real de plataforma. Para este proyecto no es especialmente importante, ya que la aplicación se desarrollará sólo para sistemas embebidos. Acceso a bases de datos utilizando un API independiente para bases de datos SQL. Esta característica tampoco es necesaria para el software a desarrollar en este proyecto. Posibilidad de desarrollo rápido de aplicaciones. La plataforma Qt proporciona herramientas de productividad como QtDesigner, una herramienta para desarrollar interfaces gráficas. Soporta internacionalización. Velocidad de ejecución (se ejecuta en código nativo). Aspecto visual (look and feel) configurable. Incluye módulos de espacio de trabajo (soporte MDI), vista de iconos, redes, XML, canvas, OpenGL,... Sin embargo, Qt fue rechazado por dos razones: Está orientado al desarrollo de interfaces gráficas basadas en la utilización de ventanas. Como se comentó en la sección anterior, la interfaz que se desarrollará no será basada en ventanas, sino que estará formada por varios menús a pantalla completa. Es una solución demasiado grande. Está pensado para realizar aplicaciones con interfaces visuales complejas y que se puedan ejecutar en diferentes plataformas. Para este proyecto interesa una solución más ajustada, para respetar las restricciones de espacio presentadas por los Set Top Boxes.

41 DirectFB DirectFB Introducción DirectFB [1] es una biblioteca ligera desarrollada teniendo en cuenta las necesidades especiales de los sistemas embebidos. Proporciona aceleración gráfica, control y abstracción de dispositivos de entrada, sistema de ventanas integrado y soporte de múltiples capas visuales sobre el dispositivo framebuffer de Linux. Es una capa de abstracción completa, que incluye la utilización de operaciones software para aquellos casos en los que la operación no esté soportada por el hardware subyacente. También proporciona un sistema de ventanas integrado, que permite la creación de ventanas translúcidas. Proporciona las siguientes operaciones gráficas aceleradas por hardware: Dibujo/relleno de rectángulos. Dibujo/relleno de triángulos. Dibujo de líneas. Copia de imágenes (blitting) tanto elástica como directa. Mezcla con un canal alpha (alpha blending). Mezcla con un valor alpha constante (alpha modulation). Nueve funciones de mezcla para el origen y el destino respectivamente. Modulación por color (colorizing). Copia basada en color (color keying) tanto para el origen como para el destino. DirectFB tiene su propia gestión de recursos de memoria de vídeo, de forma que recursos como capas visuales, dispositivos de entrada o superficies pueden ser bloqueados para acceso exclusivo. Proporciona abstracciones para los diferentes objetos gráficos, tales como capas, superficies y ventanas. Esto permite la selección entre aplicaciones basadas en ventanas o aplicaciones pensadas para pantalla completa.

42 24 Capítulo 2. Contextualización El API de DirectFB está diseñado para facilitar la creación de plugins que implementen las siguientes partes: Aceleración gráfica: Las operaciones que no puedan ser realizadas por hardware (según la implementación existente para el hardware que se esté utilizando) serán realizadas por software. Soporta las tarjetas gráficas Matrox G200/G400/G450/G550, ATI128, Vodoo 3, NeoMagic, nvidia RIVA TNT, S3 Savage y Cyber Pro, aunque para algunas no está soportada la aceleración para todas las operaciones. Cualquier otra tarjeta puede ser utilizada sin aceleración hardware, ya sea utilizando un dispositivo framebuffer específico o el framebuffer genérico VESA. Dispositivos de entrada: Permite abstraer el concepto de dispositivo de entrada, de forma que los programas no tengan que preocuparse del hardware utilizado, sólo deberán tener en cuenta los eventos generados. Actualmente, los dispositivos de entrada soportados son teclado, ratones serie y PS/2, joysticks, pantallas táctiles y dispositivos remotos por infrarrojos. Proveedor de imagen: Abstrae el concepto de imagen de forma que las aplicaciones no tengan que preocuparse del formato utilizado por la imagen que desean mostrar. Soporta los formatos JPEG, PNG, GIF y MPEG2 I-Frame. Proveedor de vídeo: La misma idea, pero para archivos de vídeo. Puede reproducir vídeos en formato MPEG1/2, AVI, Macromedia Flash y OpenquickTime. También soporta Video4Linux. Proveedor de fuentes: Permite utilizar distintos tipos de fuente de forma homogénea. Soporta el formato propio de fuentes de DirectFB y fuentes TrueType Arquitectura DirectFB utiliza la interfaz proporcionada por el dispositivo framebuffer de Linux para acceder al hardware gráfico. Hay controladores especiales para los framebuffers de ciertos dispositivos integrados en el kernel de Linux, el resto de dispositivos funcionarán también utilizando el controlador para el framebuffer VESA, pero con ciertas limitaciones. Independientemente de que se utilice aceleración gráfica o no, DirectFB utilizará el dispositivo framebuffer para realizar las siguientes operaciones: Establecer el modo de vídeo (resolución, profundidad de color y temporizaciones).

43 DirectFB 25 Mapping de la memoria del framebuffer de la tarjeta. Cambios en el área visible (viewport) del framebuffer para soportar doble buffering. De esta forma se podrán realizar cambios en un área no visible y hacerla visible de forma síncrona con el barrido del monitor para evitar efectos visuales desagradables. Si la tarjeta está soportada por DirectFB y el controlador para el chipset está presente en el kernel, DirectFB también usará el dispositivo framebuffer para las siguientes tareas: Mapping de memoria de los puertos de entrada/salida de las tarjetas. Desactivación de la aceleración interna del dispositivo framebuffer. Para ejecutar una operación gráfica específica, el controlador de DirectFB hará un mapping de los puertos de entrada/salida de la tarjeta en memoria para transmitir la operación concreta a realizar. Como se dijo en la sección 2.3.2, la aceleración hardware se programa completamente desde el espacio de usuario. Ver la figura 2.6. Aplicacion DirectFB DirectFB Espacio del Usuario Controlador para el chipset Controlador para el dispositivo framebuffer Espacio del kernel framebuffer registros de temporizacion y modo de video motor de aceleracion Hardware grafico Solo se aplica cuando se utiliza la consola del framebuffer Desactivado mientras se ejecute una aplicacion DirectFB Figura 2.6: Acceso de una aplicación DirectFB al hardware gráfico Para acceder a los dispositivos de entrada, DirectFB utiliza las interfaces estándar que Linux proporciona para los distintos dispositivos. DirectFB no accede nunca al hardware de entrada directamente.

44 26 Capítulo 2. Contextualización Términos importantes Blitting: Se refiere al proceso de copiar datos de una imagen. El caso más simple es copiar una imagen de una superficie a otra cuando ambas superficies tiene el mismo tamaño y el mismo formato de pixel. En este caso solamente tiene que ser copiada la memoria sin ningún tipo de procesado. Otros casos más avanzados son la copia elástica (stretch blitting) entre superficies de distinto tamaño, la copia con canal alpha o copia con cambio de formato de pixels. La mayoría de las tarjetas gráficas incluyen un blitter hardware capaz de realizar diversas operaciones de copia. Superficie: Es un zona de memoria reservada en la que se almacena la información sobre los pixels de una imagen en un formato específico. Una superficie puede residir en la memoria de vídeo y/o en la memoria del sistema. Es posible realizar operaciones de dibujo sobre una superficie, o copiar una superficie en otra, como se explicó anteriormente. Adicionalmente cada superficie puede utilizar un doble buffer de gráficos, de forma que las operaciones realizadas sobre ella sólo se vuelven válidas cuando se llama a una función para cambiar el buffer visible. En el modo de pantalla completa, la pantalla visible es representada por la Superficie Primaria. Esta superficie normalmente dispondrá de doble buffer para evitar efectos desagradables cuando se realicen operaciones sobre ella. Subsuperficie: Presenta el mismo interfaz que una superficie normal, pero no tiene memoria reservada para sí misma. Capa: Dependiendo del hardware gráfico, puede haber una o más capas visibles. La mayoría de las tarjetas gráficas de PC sólo disponen de una capa, pero la tarjeta de un Set Top Box puede soportar dos o más capas. Las capas ocupan diferentes posiciones en la memoria de vídeo y suelen ser combinadas utilizando mezcla alpha, esto lo hace el hardware automáticamente. Ventana: Normalmente, los contenidos de una superficie de una capa son controlados por el sistema de ventanas integrado que muestra las ventanas pertenecientes a la capa sobre un fondo configurable. Cada ventana tiene su propia superficie que es utilizada por el sistema de ventanas para componer la imagen de ventanas superpuestas. Alternativamente, las aplicaciones pueden obtener acceso exclusivo a la capa, de esta forma la aplicación tiene acceso directo a la capa y a su contenido, no se muestran ventanas ni fondos. Esta será la forma en la que se desarrollará el software de este proyecto.

45 DirectFB API El API de DirectFB está estructurado utilizando interfaces. Una interfaz es una estructura C que contiene punteros a funciones. Dependiendo de la implementación de dicha interfaz, estos punteros apuntarán a distintas funciones. Por ejemplo IDirectFBSurface puede representar la pantalla completa, los contenidos de una ventana o una subsuperficie. IDirectFB es la Super Interfaz. Es la única que puede ser creada por una función global (DirectFBCreate). El resto de interfaces serán creadas llamando a funciones de IDirectFB o a funciones de interfaces ya creadas. Se puede acceder a las interfaces existentes (por ejemplo los dispositivos de entrada) a través de IDirectFB. En la figura 2.7 se puede observar la relación entre las distintas interfaces de DirectFB. «super interface>> IDirectFB Obtener Crear Obtener Crear IDirectFBDisplayLayer Crear IDirectFBWindow Obtener Obtener IDirectFBSurface IDirectFBInputBuffer IDirectFBInputDevice Crear Figura 2.7: Relación entre las interfaces de DirectFB IDirectFBImageProvider IDirectFBVideoProvider IDirectFBFont Ciertas interfaces están implementadas como módulos que serán cargados en tiempo de ejecución en caso de que sea necesario. Las interfaces implementadas de esta forma son IDirectFBImageProvider, IDirectFBVideoProvider e IDirectFBFont. La aplicación cargará la implementación necesaria en cuando se construya la interfaz. Otras interfaces también implementadas como módulos serán cargadas durante la inicialización de la aplicación. Estas interfaces son IDirectFBInputDevice y GfxCard (interfaz interna inaccesible para las aplicaciones, que contiene el código encargado de utilizar la aceleración hardware en caso de que sea posible). De esta forma se podrán añadir nuevas implementaciones de controlador de aceleración, dispositivos de entrada y proveedores de medios sin necesidad de recompilar ni DirectFB ni la aplicación.

46

47 Capítulo 3 Análisis Índice General 3.1. Introducción Protocolo de comunicación Set Top Box Aplicación DFBCIn Introducción Módulo gráfico Parser Conclusiones Servidor XML (VXMLS) Ciclo de Desarrollo Introducción Prototipo DFBCIn VXMLS Prueba del sistema conjunto Introducción El objetivo principal de este proyecto es el desarrollo de un sistema que permita al usuario final el acceso de forma controlada a los medios disponibles en el 29

48 30 Capítulo 3. Análisis servidor de VoD VoDKA. Por lo tanto, se necesita un dispositivo que actúe como mediador entre el usuario y el servidor VoD. Es deseable que dicha interacción pueda ser controlada de forma remota y centralizada, de forma que pueda adaptarse según las condiciones del entorno. Esto nos lleva a la necesidad de implementar otro dispositivo adicional que permita definir el protocolo de interacción que se presentará al usuario. Así pues, este proyecto se analizará dividido en dos subproyectos: el desarrollo de un Set Top Box y el de un servidor que proporcione a dicho Set Top Box la información necesaria para controla la interacción con el usuario. Esta separación supone la necesidad de definir un protocolo de comunicación entre el Set Top Box y el servidor de definiciones de interfaz. Para establecer dicho protocolo, se han utilizado los estándares HTTP [35] y XML [36], lo que permitirá la utilización de herramientas ya existentes para el desarrollo del software necesario Protocolo de comunicación Para definir el protocolo de comunicación entre el Set Top Box y el servidor de definiciones de interfaz se necesita especificar: El sistema de comunicación: Se utilizará el protocolo HTTP sobre una conexión TCP convencional. El Set Top Box actuará como cliente, solicitando la información que necesite mediante peticiones HTTP al servidor. La estructura de la información: Se utilizará el estándar XML. El servidor devolverá la información requerida por el cliente enviando un documento XML en una respuesta HTTP. El estándar XML permite especificar la estructura que debe tener un documento de forma independiente de su contenido. Hay diferentes formas de expresar la estructura de un documento XML, en este proyecto se utilizarán DTDs [36] para definir la forma en la que los documentos deben expresar la información requerida. El servidor de definiciones de interfaz (servidor XML de aquí en adelante) necesitará expresar dos tipos de respuestas: la definición de la interfaz solicitada por el Set Top Box y los mensajes de confirmación o de error para el resto de

49 Aplicación DFBCIn 31 operaciones que el Set Top Box pueda solicitarle (por ejemplo, iniciar la sesión). La estructura del documento de confirmación simplemente tiene que comprobar dos casos: éxito o fracaso. Los documentos utilizados para definir la interfaz son bastante más complejos. Deben poder expresar tanto el aspecto visual como la funcionalidad a realizar por la interfaz definida. Por lo tanto, debe diseñarse una estructura que sea fácilmente extensible, para no constreñir el aumento de funcionalidades del Set Top Box Set Top Box El desarrollo del Set Top Box debe tener como objetivo un sistema que sea capaz de realizar las siguientes tareas: Comunicarse con el servidor VXMLS para obtener la información necesaria sobre la interfaz a presentar al usuario. Esta interfaz debe lo suficientemente clara y sencilla, de forma que no suponga ninguna dificultad para cualquier tipo de usuario. Presentar dicha interfaz al usuario en un televisor convencional y permitirle interactuar con ella a través de un mando a distancia. Reproducir vídeo recibido del servidor VoD VoDKA. Debe ser un sistema razonablemente económico. El software se desarrollará de forma que no sea dependiente de la plataforma, deberá ser posible ejecutarlo en cualquier Set Top Box que disponga de una salida para televisión y una tarjeta de red. Como sistema operativo se utilizará Linux. Para respetar las restricciones de espacio será necesario evitar el sistema X Windows, por lo que la programación gráfica se hará accediendo directamente al hardware mediante el dispositivo framebuffer de Linux (ver la sección 2.3). Para controlar la interacción con el usuario y la comunicación con el servidor XML se desarrollará una única aplicación llamada DFBCIn (DirectFB C Interface). La comunicación con el servidor VoD se ocultará al resto del sistema utilizando el proyecto desarrollado en [37] que permite manejar un vídeo servido con el método de streaming como si se tratara de un fichero local.

50 32 Capítulo 3. Análisis 3.4. Aplicación DFBCIn Introducción El objetivo de esta aplicación es el de controlar la interacción entre el usuario y los contenidos del servidor de streaming VoDKA. Se puede dividir el análisis de esta aplicación en tres módulos que deberán estar bien desacoplados: El módulo gráfico: Se encargará de controlar el aspecto gráfico de la interfaz mostrada al usuario. Como se verá en la sección 3.4.2, este módulo también deberá controlar los dispositivos de entrada. El módulo VXMLS: Se encargará de enviar las peticiones necesarias a VXMLS y de transformar los ficheros XML recibidos en una estructura de datos comprensible para el resto de la aplicación. Para ello deberá implementar un parser para interpretar los documentos recibidos. El motor de la aplicación: Se encargará de ejecutar las acciones solicitadas por el usuario. Este módulo accederá a los dos anteriores a través de un API definido y estable Módulo gráfico Para la programación gráfica se ha elegido la librería DirectFB [1] (en la sección 2.4 se hace una pequeña introducción). El desarrollo se hará utilizando el lenguaje de programación de medio nivel C. De esta forma, se aligera notablemente la carga, tanto de ejecución como de espacio, pero la codificación se vuelve mucho más complicada que si se utilizara un lenguaje de más alto nivel y el sistema X Windows. Durante la fase de análisis se ha desarrollado una pequeña aplicación para validar la utilidad de la biblioteca DirectFB, de acuerdo con los objetivos del proyecto. En dicha aplicación se comprobó el comportamiento de DirectFB en una aplicación multi-hilo en la que se puede reproducir un vídeo elegido mediante un menú gráfico. En esta aplicación se resumía la funcionalidad que es necesario implementar en la aplicación DFBCIn con la ayuda de esta biblioteca, obviando el resto de objetivos que se implementarán de forma independiente a la utilización de DirectFB. En la figura 3.1 se muestra el ciclo de interacción implementado en este prototipo.

51 Aplicación DFBCIn 33 También se han realizado pequeñas aplicaciones de prueba para comprobar que DirectFB permite el acceso concurrente de varios hilos de programación a sus recursos, que es capaz de reproducir varios vídeos al mismo tiempo (se comprobó que sólo puede reproducir varios vídeos si sólo uno contiene audio) y su comportamiento ante fallos de la aplicación. Figura 3.1: Prototipo de interfaz con el usuario Además, para el desarrollo de la aplicación anterior se tomaron como referencia algunas aplicaciones ya existentes implementadas utilizando DirectFB, lo que ayudó a afrontar la codificación de DFBCIn con buen conocimiento del API y del estilo de codificación a seguir en la parte gráfica. La utilización de DirectFB proporciona algunas ventajas interesantes: Está diseñada siguiendo el paradigma de orientación a objetos, lo que facilita la traducción del diseño a la codificación. Proporciona numerosas abstracciones que desacoplan el código desarrollado de aspectos tales como la aceleración hardware o la decodificación de vídeo. Permite el control de diversos dispositivos de entrada, entre ellos de puerto de infrarrojos. De esta forma, para el código desarrollado, no hay diferencia entre el mando a distancia y el teclado. El API es claro, sencillo y orientado a objetos. La documentación, aunque no excelente, es suficiente y está actualizada.

52 34 Capítulo 3. Análisis Pero también trae consigo una serie de contratiempos, la mayoría derivados de la utilización de un lenguaje de bajo nivel y con numerosos efectos colaterales como es C: Es necesario programar de forma explícita la reserva y liberación de memoria, ya que C no aporta un sistema de recolección de basura. C no es orientado a objetos, la traducción de los objetos del diseño es más complicada que si se utilizara un lenguaje moderno de más alto nivel. La combinación de los dos puntos anteriores hace que la compartición del mismo objeto entre distintos módulos de la aplicación tenga que ser controlada de forma explícita (es necesario asegurarse de que el objeto se libera solamente una vez cuando deje de ser necesario). El lenguaje C también obliga a hacer explícito el control de errores ya que no aporta ningún sistema de control de excepciones. La biblioteca DirectFB está actualmente en estado de desarrollo, por lo que será necesario tener un especial cuidado en el diseño para asegurar que los cambios sufridos por dicha biblioteca sólo afecten al módulo gráfico de DFBCIn y no se propaguen por el resto de la implementación. DirectFB controla tanto el hardware gráfico como los dispositivos de entrada. Esto hace imposible separar físicamente los módulos de entrada de los de salida en el diseño del sistema. El módulo de entrada queda definitivamente ligado a la utilización o no de DirectFB en el de salida. Como es necesario independizar el módulo gráfico del resto de la aplicación, el diseño del sistema de entrada quedará vinculado al módulo gráfico. Un fallo en el proceso de liberación de recursos puede hacer que DirectFB deje el sistema inestable, siendo necesaria su recuperación de forma remota Parser Para interpretar los documentos XML recibidos del servidor VXMLS es necesario implementar un parser, para ello se ha utilizado la biblioteca expat [2] que proporciona una implementación de un parser XML genérico que se puede particularizar utilizando la idea del patrón Strategy [38].

53 Aplicación DFBCIn 35 VXMLS puede devolver dos tipos de documentos, los utilizados para especificar la interfaz con el usuario 1 y los que certifican el éxito de operaciones sin resultado. En la figura 3.2 se puede ver cómo se pueden obtener distintos parsers utilizando expat. XML_Parser +XML_parse(): UserData #startelement(userdata:userdata,tagname:string,attributes:array) #EndElement(userData:UserData,tagName:String) #characterdata(userdata:userdata,text:string,length:integer) MenuParser +parse(stream:characterstream): Menu -startelement(userdata:userdata,tagname:string,attributes:array) -EndElement(userData:UserData,tagName:String) -characterdata(userdata:userdata,text:string,length:integer) VXMLSParser +parse(stream:characterstream): Boolean -startelement(userdata:userdata,tagname:string,attributes:array) -EndElement(userData:UserData,tagName:String) -characterdata(userdata:userdata,text:string,length:integer) Figura 3.2: Creación de parsers con expat La aproximación a este diseño utilizando el lenguaje C presenta algunas complicaciones. La solución propuesta por expat proporciona una función que devuelve un objeto de tipo XML Parser en el que se deben instalar unos manejadores para los eventos startelement, endelement y characterdata. Dado que la estructura de los documentos a analizar puede ser arbitrariamente profunda, será necesario utilizar una pila para ir almacenando la información a medida que el parser va llamando los manejadores proporcionados. Además, el número de etiquetas que pueden ser utilizadas en los documentos que definen la interfaz es bastante elevado (y aumentará a medida que aumente la funcionalidad del sistema), por lo que se deberá poner especial cuidado en la estructuración del código del parser para evitar la duplicación del mismo. También se debe tener en cuenta que el diseño debe quedar abierto de forma que se pueda añadir fácilmente el código necesario para interpretar las nuevas etiquetas que vayan surgiendo a lo largo del ciclo de vida del proyecto Conclusiones El diseño de la aplicación DFBCIn debe perseguir los siguientes objetivos: Aislar lo más posible la utilización de DirectFB para minimizar el impacto de los posibles cambios en dicha biblioteca. 1 La especificación de la interfaz se hará definiendo una sucesión de menús, como se verá en apartados posteriores. Por ello, el parser que se utilizará para este tipo de documentos devuelve objetos Menu

54 36 Capítulo 3. Análisis La comunicación con VXMLS también deberá ser desacoplada al máximo del resto de la aplicación para evitar que los cambios en VXMLS se propaguen por el código de DFBCIn. Permitir la extensión de la funcionalidad ofrecida con poco esfuerzo. A pesar de que el desarrollo se haga en C, el diseño será objetual Servidor XML (VXMLS) El objetivo de esta aplicación es atender las peticiones de las aplicaciones DFBCIn residentes en Set Top Boxes remotos, responderles con el correspondiente documento XML y mantener una base de datos con información, tanto de los medios disponibles en VoDKA como información referente a los usuarios. La funcionalidad ofrecida por el servidor será muy básica, simplemente la necesaria para comprobar el correcto funcionamiento de la aplicación DFBCIn y demostrar las posibilidades que ofrece el hecho de mantener la información sobre la interfaz con el usuario centralizada en un servidor remoto. El desarrollo del servidor se ha hecho utilizando el lenguaje funcional Erlang [3] y algunas herramientas proporcionadas por la plataforma de desarrollo Erlang/OTP [4]. Concretamente: el contenedor de aplicaciones HTTP Inets [39], el sistema gestor de bases de datos distribuido Mnesia [40] y el lenguaje de consulta Mnemosyne [41]. La aplicación VXMLS debe ser capaz de realizar las siguientes operaciones: Mantener sesiones para los diferentes usuarios conectados. Mantener información sobre los usuarios en la base de datos. Mantener información sobre los medios disponibles en VoDKA. Generar documentos XML de forma dinámica, dependiendo del contexto actual. Permitir a los usuarios configurar sus preferencias. Las posibilidades de personalización implementadas son la selección de idioma y la selección de perfil, de forma que cada Set Top Box puede mantener información sobre varios usuarios.

55 Ciclo de Desarrollo 37 La definición de interfaz que debe proporcionar VXMLS permitirá acceder a las posibilidades de personalización anteriores y a la reproducción de vídeos, que se mostraran clasificados como novedades, vistos y antiguos. Dentro de cada una de estas clasificaciones, los vídeos estarán clasificados en géneros. El servidor también deberá encargarse de mover los vídeos vistos por el usuario a la sección vistos Ciclo de Desarrollo Introducción Una vez establecidos los requisitos que debe cumplir el sistema final, se debe elegir el ciclo de desarrollo que se seguirá para llevar a cabo este proyecto: 1. Desarrollo de un prototipo que demuestre la utilidad de DirectFB. El prototipo diseñado deberá dibujar menús, controlar la entrada del usuario y reproducir vídeo. Estas son las operaciones que serán implementadas con la ayuda de DirectFB en la aplicación DFBCIn. También se ha codificado un parser mínimo para comprobar la utilidad de la biblioteca expat empleada en la codificación del parser XML. 2. Desarrollo de una primera versión de la aplicación DFBCIn que trabaje con ficheros XML estáticos en lugar de obtenerlos del servidor dinámico VXMLS. 3. Desarrollo de la aplicación VXMLS. 4. Desarrollo de un nuevo incremento de DFBCIn que se comunique con VXMLS para obtener la información sobre la interfaz con el usuario a utilizar. 5. Refinamiento de DFBCIn y de VXMLS en conjunto Prototipo Para comprobar que realmente se puede llevar a cabo la implementación gráfica utilizando DirectFB se desarrolló un prototipo en el que solamente se programó la parte gráfica de una posible aplicación para el Set Top Box. Este prototipo simplemente muestra una serie de menús (que no están especificados por ninguna fuente externa) que permiten la elección de una imagen de

56 38 Capítulo 3. Análisis fondo o la reproducción de un vídeo. Para la programación de este prototipo se ha consultado el código fuente de algunas aplicaciones de ejemplo implementadas utilizando DirectFB. Una de ellas es el reproductor de vídeo DFBSee (figura 3.3) y otra es DFBPoint (figura 3.4), que muestra una presentación de transparencias a partir de una especificación XML. Figura 3.3: Aplicación DFBSee En el código de la aplicación DFBSee se puede ver cómo programar un sistema que reproduzca vídeo y permita al usuario realizar acciones tales como pararlo, avanzarlo o ver una barra de progreso. La aplicación DFBPoint resulta útil para hacerse una idea de cómo programar la presentación de menús. Implementa un parser específico para los documentos XML que utiliza, por lo que esta parte no se tendrá en cuenta para la aplicación DFBCIn, en la que se utilizará la biblioteca expat para la implementación del parser. Tras el estudio de estas dos aplicaciones, se ha desarrollado el prototipo, lo que permite afrontar el diseño de la aplicación DFBCIn con los conocimientos necesarios para ocultar lo más posible la utilización de DirectFB a los módulos que no precisan el acceso al hardware gráfico.

57 Ciclo de Desarrollo 39 Figura 3.4: Aplicación DFBPoint Para verificar la utilidad de la biblioteca expat se ha codificado un pequeño programa que muestra por pantalla los distintos eventos que detecta el parser genérico proporcionado por expat. La implementación del parser para DFBCIn deberá sustituir estos mensajes por las operaciones a realizar DFBCIn Para el desarrollo de la aplicación DFBCIn se ha seguido el paradigma de programación incremental. En primer lugar se desarrollará el núcleo de la aplicación y a partir del momento en que el núcleo haya sido validado con las pruebas correspondientes, se continuará con el desarrollo de nuevos incrementos que vayan aumentando la funcionalidad proporcionada por la aplicación. El paradigma de desarrollo incremental se adapta bien al tipo de software a desarrollar, ya que uno de los requisitos planteados para la aplicación DFBCIn es que se pueda extender la funcionalidad ofrecida a medida que vayan surgiendo nuevas ideas o necesidades. Seguir un desarrollo incremental obliga de forma explícita a que el diseño soporte la creación de nuevas versiones con nuevas características a partir de las versiones anteriores. Uno de los principales problemas del desarrollo incremental es la definición

58 40 Capítulo 3. Análisis de lo que será el núcleo de la aplicación. Para el caso de DFBCIn, el primer incremento tendrá como objetivo un sistema que pueda interpretar documentos XML estáticos localizados en ficheros locales que definan una interfaz muy sencilla en la que lo único que se pueda hacer sea la navegación por los menús. En este incremento ya se contemplan varias de las funcionalidades importantes que se esperan de DFBCIn: la interpretación de documentos XML, la presentación gráfica de menús y el control de entrada por parte del usuario. Se dejarán para incrementos posteriores la comunicación con un sistema remoto para la obtención de los documentos XML y la reproducción de vídeo VXMLS Puesto que el desarrollo de VXMLS se empezará cuando el desarrollo de DFBCIn ya esté suficientemente avanzado, a esas alturas se se tendrá una definición bastante estable de la estructura de los documentos XML a servir y de las posibilidades esperadas de la interfaz definida. Por lo tanto, el desarrollo del servidor VXMLS podrá hacerse en un único incremento con sus correspondientes etapas de análisis, diseño, codificación y prueba Prueba del sistema conjunto Una vez terminado el desarrollo de DFBCIn y de VXMLS, se realizaron las pruebas de ambos sistemas en conjunto (una vez hechos los cambios necesarios en DFBCIn para que se comunique correctamente con VXMLS), tras las cuales se ha desarrollado el último incremento de ambas aplicaciones hasta tener el sistema final funcionando correctamente.

59 Capítulo 4 Diseño Índice General 4.1. Introducción Definición de la interfaz y objetos del dominio Introducción La clase Menu La interfaz Action Documentos XML Introducción Descripción de los menús Protocolo de comunicación Diseño de DFBCIn División en subsistemas Interacción entre módulos Objetos comunes Diseño del motor de la aplicación Diseño del módulo VXMLS Diseño del módulo gráfico Diseño de VXMLS Introducción Objetos del dominio Modelo entidad-relación Diseño de la capa modelo

60 42 Capítulo 4. Diseño Diseño de la vista y el controlador Introducción Antes de proceder al diseño de las aplicaciones VXMLS y DFBCIn y del sistema que utilizarán para comunicarse, es necesario describir qué es lo que se entenderá por descripción de interfaz, es decir, hay que especificar qué es lo que VXMLS tiene que enviar a DFBCIn. Una vez establecida la definición de lo que se entenderá cómo interfaz, se debe hacer el diseño de los objetos que conformarán el dominio (los objetos comunes a ambas aplicaciones). Tras los dos pasos anteriores ya se tendrá hecho el diseño de la parte común a VXMLS y DFBCIn. Será necesario diseñar el protocolo de comunicación que ambas deberán cumplir. Una vez hecho esto se podrá comenzar el diseño de ambos sistemas por separado Definición de la interfaz y objetos del dominio Introducción Como ya explicó en la sección 3.1, la aplicación VXMLS debe proporcionarle a DFBCIn una especificación de la interfaz a utilizar para comunicarse con el usuario. Antes de empezar el diseño de cualquier otra parte del sistema es necesario definir con claridad cómo se va a describir exactamente dicha interfaz con el usuario. Se pretende que la interfaz sea sencilla y que el usuario interactúe utilizando un mando a distancia. También es deseable que el número de botones necesario para acceder a la funcionalidad básica sea mínimo. Por lo tanto, la idea inicial de interfaz con el usuario será una sucesión de menús en los cuales el usuario deberá elegir entre las opciones disponibles. La interfaz será una generalización de la desarrollada para el prototipo implementado en la fase de análisis (ver la figura 3.1).

61 Definición de la interfaz y objetos del dominio La clase Menu Así pues, se entenderá como descripción de interfaz la descripción de la sucesión de menús que se irán mostrando al usuario. La clase Menu será la que defina los objetos que utilizará VXMLS para indicarle a DFBCIn la interfaz que deberá mostrar. Es decir, VXMLS generará objetos Menu y los transmitirá serializados (en forma de documentos XML) a la aplicación cliente DFBCIn. En la figura 4.1 se muestra una primera aproximación a la clase Menu. Menu header: String + draw() 1.. Option + text: String + execute() Figura 4.1: Primera aproximación a la clase Menu Sin embargo, siguiendo este diseño, la información sobre las acciones a realizar por cada opción estaría codificadas en el método execute, lo que obligaría a especializar una nueva clase para cada opción de cada menú. Aplicando el patrón de diseño Command [38], se definirá una nueva interfaz Action, que representará una acción genérica a realizar cuando se selecciona una opción. En la figura 4.2 se puede ver la aproximación utilizada para definir los objetos Option. Menu header: String + draw() Option text: String + execute() for all actions do action.execute end 1.. <<interface>> Action + execute() NextMenuAction nextmenu: String + execute() PreviousMenuAction depth: Int + execute() Figura 4.2: Segunda aproximación a la clase Menu La interfaz Action proporciona la extensibilidad que se exigió en el análisis

62 44 Capítulo 4. Diseño referente a la funcionalidad ofrecida por el Set Top Box. En los diferentes subsistemas que componen el proyecto se deberá implementar este diseño preservando la posibilidad de añadir nuevas acciones manteniendo una interfaz común, de forma que estas nuevas acciones no afecten al resto del sistema. Además, la interfaz Action será utilizada para definir las acciones a realizar en otros casos, además de la ejecución de opciones seleccionadas por el usuario. El diseño definitivo de la clase Menu es el especificado en la figura 4.3 Menu + majorversion: Int + minorversion: Int header: String time: Int Option 1.. text: String + execute() for all actions do action.execute end + draw() initactions 0.. Action 1.. <<interface>> timeactions 0.. * + execute() NextMenuAction nextmenu: String + execute() PreviousMenuAction depth: Int + execute() Figura 4.3: Diseño definitivo de la clase Menu Los atributos majorversion y minorversion se utilizarán para controlar las nuevas implementaciones de la clase Menu que VXMLS vaya siendo capaz de servir. En el caso de que DFBCIn reciba un menú de una versión mayor a la que sea capaz de soportar deberá actualizar su implementación de forma que pueda interpretar las nuevas características de la clase Menu (idealmente, estas nuevas características sólo deberían ser nuevas implementaciones de la interfaz Action). Las acciones initactions se ejecutarán cada vez que DFBCIn cargue un nuevo objeto de la clase Menu. El atributo time indicará (en caso de que sea necesario) el tiempo a esperar desde que se carga el menú hasta que se ejecuten las acciones timeactions. La espera se reiniciará cada vez que se reciba alguna entrada por parte del usuario.

63 Definición de la interfaz y objetos del dominio La interfaz Action Acciones implementadas El primer incremento de la aplicación DFBCIn solamente pretende conseguir una interfaz en la que el usuario pueda navegar por los menús, sin ninguna otra posibilidad. Para ello, inicialmente sólo se necesitará implementar una acción para pasar a un nuevo menú y otra para volver a menús anteriores (NextMenuAction y PreviousMenuAction respectivamente, inicialmente ChangeOptionAction estará codificada directamente como respuesta a la pulsación de las teclas arriba y abajo). Además de las dos acciones citadas anteriormente, el sistema final contiene las siguientes implementaciones de Action: PlayVideoAction: Inicia la reproducción de un vídeo. StopVideoAction: Detiene la reproducción en curso. ResumeVideoAction: Continúa con la reproducción de vídeo. SeekVideoAction: Salta a un momento específico del vídeo que se está reproduciendo. UnloadVideoAction: Termina la reproducción de vídeo. HideMenuAction: Oculta el menú de forma que no sea visible en la pantalla. ReloadMenuAction: Vuelve a solicitar el menú actual a VXMLS. ShowMenuAction: Muestra el menú actual en la pantalla. ChangeOptionAction: Cambia la opción seleccionada en el menú actual. BindKeyAction: Enlaza una tecla a un grupo de acciones a realizar en caso de que el usuario la pulse. SetPropertyAction: Cambia el valor de un parámetro de configuración. ShowTextAction: Muestra texto en la pantalla. HideTextAction: Oculta el texto mostrado en la pantalla. LoadMp3Action: Inicia la reproducción de un fichero de audio mp3. PauseContinueMp3Action: Detiene o continua la reproducción de audio. KillMp3Action: Elimina el reproductor de mp3 para que permitir a otros subsistemas utilizar la tarjeta de sonido.

64 46 Capítulo 4. Diseño Acciones para el manejo de menús Action <<interface>> + execute() ReloadMenuAction + execute() HideMenuAction + execute() ShowMenuAction + execute() NextMenuAction nextmenu: String arguments: Array PreviousMenuAction returndepth: Int reinit: Bool + execute() + execute() Figura 4.4: Acciones para el manejo de menús En la figura 4.4 está representado el diseño de las acciones a implementar para controlar la navegación por los menús de la interfaz. ReloadMenuAction, ShowMenuAction y HideMenuAction solamente deberán realizar acciones sobre el menú actual y no necesitan ningún tipo de atributos. NextMenuAction tiene como atributos el nombre del menú a cargar (DFBCIn solicitará un menú con ese nombre a VXMLS) y una lista de argumentos. La lista de argumentos se añadió al diseño durante la etapa de diseño de VXMLS, para permitir generalizar la generación de menús similares, por ejemplo, para generar un menú en el que las opciones sean una lista de películas, DFBCIn solicitará un menú lista de películas con los atributos género y filtro. La acción PreviousMenuAction tiene como atributos returndepth, que indica el número de menús que se debe volver atrás y reinit, para indicar si se debe reinicializar el menú al que se retorna o se deben mantener sus propiedades actuales Acciones para el control de vídeos En la figura 4.5 se puede ver el diseño de las acciones utilizadas para controlar la reproducción de vídeo. Las acciones ResumeVideoAction, UnloadVideoAction y StopVideoAction no tienen ningún parámetro, simplemente deben actuar sobre la reproducción en curso. La acción SeekVideoAction tiene como atributos mode, que indica cómo se quiere posicionar el vídeo (puede ser forward para avanzar, backward para retro-

65 Definición de la interfaz y objetos del dominio 47 Action <<interface>> 1.. endactions + execute() SeekVideoAction ResumeVideoAction StopVideoAction UnloadVideoAction PlayVideoAction mode: String time: Int + execute() + execute() + execute() + execute() video: String + execute() Forward, Backward o Absolute Figura 4.5: Acciones para el control de vídeos ceder o absolute para ir a un momento específico de la reproducción), y time, que indica o bien el tiempo que se debe avanzar o retroceder, o bien el momento al que se debe saltar. La acción PlayVideoAction es una aplicación del patrón Composite [38]. Como atributo tiene el nombre del vídeo a reproducir (video). Al finalizar la reproducción del vídeo, se ejecutaran las acciones endactions Otras acciones En la figura 4.6 se describe el diseño del resto de acciones que se han implementado para el sistema final. Action <<interface>> 0.. keyactions + execute() ACTIONS NULL EXECUTE KillMp3PlayerAction SetPropertyAction ChageOptionAction BindKeyAction + execute() name: String value: Int absolute: Bool value: Int type: String key: String + execute() + execute() + execute() ShowTextAction PauseContinueMp3Action LoadMp3Action HideTextAction lines: Array + execute() + execute() path: String + execute() + execute() Figura 4.6: Resto de acciones del sistema SetPropertyAction tiene como atributos el nombre de la propiedad a modificar (name) y el nuevo valor que debe tomar esa propiedad (value).

66 48 Capítulo 4. Diseño ChangeOptionAction tiene como atributos un entero y un valor booleano para indicar si el valor value se debe sumar a la opción actual o si es la acción que hay que seleccionar. ShowTextAction tiene como atributos un array de líneas de texto. LoadMp3Action tiene como atributo la ruta completa del fichero mp3 a reproducir. Las acciones HideTextAction, PauseContinueMp3Action y KillMp3Player no necesitan atributos para ser ejecutadas Documentos XML Introducción Se necesitan dos tipos de documentos XML, uno de ellos se utilizará para confirmar aquellas operaciones para las que VXMLS no devuelve un objeto de la clase Menu y otro para interpretar las descripciones de los objetos Menu. La estructura de estos documentos que describen respuestas de VXMLS es muy simple, consisten en la etiqueta raíz vxmls con, bien una etiqueta ok anidada para confirmar la operación, bien una etiqueta error con un mensaje de error anidado para indicar un fallo en la operación. La estructura de los documentos que describen un objeto de la clase Menu son bastante más complejos y se explicarán en la siguiente sección. En el apéndice A se pueden ver los DTDs que especifican la estructura de ambos documentos Descripción de los menús Introducción La estructura de los documentos XML utilizada para la descripción de los menús debe atenerse al hecho de que el número de acciones irá aumentando con el paso del tiempo.

67 Documentos XML 49 La interfaz Action será representada por la etiqueta action que no tiene argumentos. Anidadas dentro de esta etiqueta irán las etiquetas específicas de cada acción a realizar. De esta forma se mantiene la idea del diseño de mostrar todas las acciones bajo una interfaz común Descripción del menú Teniendo en cuenta la clase Menu diseñada en el apartado 4.2, los documentos XML utilizados para definir un objeto perteneciente a dicha clase podrán contener las siguientes etiquetas (ver apéndice A). header: Contendrá el texto a mostrar como título del menú. version: Versión de la definición de menú utilizada, DFBCIn deberá actualizarse cuando reciba un menú con una versión mayor a la que soporte. timer: Tiene un atributo time que indica el tiempo a esperar sin recibir eventos del usuario antes de ejecutar las acciones contenidas por esta etiqueta. initactions: Anidadas en esta etiqueta están las acciones a realizar en el momento en que se cargue el menú. option: Representa a la clase option, tendrá anidadas las etiquetas: text Contiene el texto a mostrar al usuario para identificar la opción. action Cada opción tendrá anidado un número de etiquetas de este tipo para definir las acciones a realizar cuando se seleccione dicha opción. Las etiquetas que describen cada implementación de la interfaz Action. Por ejemplo, las siguientes etiquetas XML describen un menú con un bloque de acciones a realizar en el momento en el que sea cargado, otro bloque de acciones que se ejecutarán en caso de que pasen diez segundos sin que se detecte ningún evento y dos opciones (el contenido de las etiquetas action se explica en la siguiente sección): <menu> <header>menu de ejemplo</header> <version>0.0</version> <initactions>

68 50 Capítulo 4. Diseño <action>...</action> <action>...</action> </initactions> <timer seconds="10"> <action>...</action> </timer> <option> <text>primera opción</text> <action>...</action> <action>...</action> </option> <option> <text>segunda opción</text> <action>...</action> </option> </menu> Descripción de las acciones Anidadas dentro de la etiqueta action se encontrarán las etiquetas que describen cada acción específica. Cada etiqueta que represente a una acción deberá describir, ya sea mediante atributos, texto o nuevas etiquetas anidadas, un objeto perteneciente a la clase implementación de Action correspondiente (ver la sección 4.2.3). Las etiquetas que describen las distintas acciones son las siguientes: nextmenu: Representa una acción de tipo NextMenuAction, nextmenu contiene el valor del atributo con el mismo nombre del objeto que se está definiendo. Para especificar los argumentos que se deben pasar a VXMLS cuando se solicita el menú se utilizarán etiquetas menuargument anidadas en el interior de la etiqueta nextmenu. Estas etiquetas nextargument deben tener los siguientes atributos: name: Nombre del argumento. value: Valor del argumento. Por ejemplo, una acción para solicitar el menú movie list menu con los atributos filter=shown y genre=adventure se utilizará una etiqueta como esta:

69 Documentos XML 51 <action> <nextmenu name="movie_list_menu"> <menuargument name="genre" value="adventure"/> <menuargument name="filter" value="shown"/> </nextmenu> </action> previousmenu: Describe una acción de tipo PreviousMenuAction. Contiene los atributos depth, que contiene el valor de atributo returndepth del objeto definido, y reinit, que representa al atributo con el mismo nombre de la clase PreviousMenuAction. hidemenu: Representa una acción de tipo HideMenuAction. showmenu: Representa una acción de tipo ShowMenuAction. reloadmenu: Representa una acción de tipo ReloadMenuAction. changeoption: Describe una acción de tipo ChangeOptionAction. Para definir los atributos del objeto a crear, esta etiqueta contiene dos atributos: value, que representa al atributo value del objeto, y mode. El atributo mode puede ser relative con lo que el atributo absolute del objeto creado sería falso, o relative, con lo que el atributo absolute del objeto sería verdadero. playvideo: Se utiliza para describir acciones del tipo PlayVideoAction. Contiene un único atributo file que contiene la referencia al vídeo a reproducir (atributo video de la clase PlayVideoAction). Anidadas dentro de esta etiqueta habrá otras etiquetas action, que representan las acciones a ejecutar cuando la reproducción de vídeo alcance su fin. Por ejemplo, las siguientes etiquetas definen una acción que inicia la reproducción de un vídeo de forma que cuando finalice se carga un nuevo menú se muestra por encima del vídeo ya parado. <action> <playvideo file="video.avi"> <action> <stopvideo/> </action> <action> <nextmenu name="video_end_menu"> </nextmenu>

70 52 Capítulo 4. Diseño </action> <action> <showmenu/> </action> </playvideo> </action> stopvideo: Representa una acción de tipo StopVideoAction. resumevideo: Representa una acción de tipo ResumeVideoAction. unloadvideo: Representa una acción de tipo UnloadVideoAction. seekvideo: Representa una acción de tipo SeekVideoAction. Para especificar los atributos del objeto a crear, esta etiqueta contiene dos atributos: mode, que define el valor de atributo con el mismo nombre del objeto a crear, y time, que define el valor del atributo time de dicho objeto. El atributo mode podrá tomar los valores forward, backward o absolute. bindkey: Describe una acción de tipo BindKeyAction. Como atributos únicamente tiene key que especifica la tecla que se quiere enlazar. Para definir a qué se quiere enlazar dicha tecla, una etiqueta bindkey puede contener una de estas dos etiquetas: keyactions: Anidadas dentro de esta etiqueta irán un cierto número de etiquetas action que representan las acciones a ejecutar cuando el usuario pulse la tecla en cuestión. Por ejemplo, para hacer que una pulsación de la tecla UP cambie la opción seleccionada por la opción anterior: <action> <bindkey key="up"> <keyactions> <action> <changeoption value="-1" mode="relative"/> </action> <action> <showmenu/> </action> </keyactions> </bindkey> </action>

71 Protocolo de comunicación 53 keyevent: Tiene un atributo type que define el comportamiento que debe seguir DFBCIn cuando un usuario pulse la tecla vinculada. Los valores que puede tomar type son: EXECUTE: Indica que se de deben ejecutar las acciones vinculadas a la opción actualmente seleccionada. NULL: La pulsación de una tecla vinculada a un evento NULL no provoca ningún tipo de reacción en DFBCIn. Por ejemplo, para hacer que el botón SEL provoque la ejecución de las acciones de la opción seleccionada: <action> <bindkey key="sel"> <keyevent type="execute"/> </bindkey> </action> setproperty: Representa una acción de tipo SetPropertyAction. Para describir el objeto a crear, esta etiqueta utiliza los atributos name y value, cuyos nombres son idénticos a los de los atributos del objeto que se está definiendo. showtext: Representa una acción de tipo ShowTextAction. Contiene un grupo de etiquetas textline que describen las líneas de texto a mostrar. Por ejemplo, para describir una acción que muestra el resumen de una película: <action> <showtext> <textline>habiendo marchado en busca de</textline> <textline>fortuna y después de unos</textline> <textline>a~nos...</textline> </showtext> </action> hidetext: Representa una acción de tipo HideTextAction. loadmp3: Representa una acción de tipo LoadMp3Action. Contiene el atributo path para describir el atributo con el mismo nombre del objeto definido. pausecontinuemp3: Representa una acción de tipo PauseContinueMp3Action. killmp3player: Representa una acción de tipo KillMp3PlayerAction.

72 54 Capítulo 4. Diseño 4.4. Protocolo de comunicación La comunicación entre DFBCIn y VXMLS se hará siguiendo el estándar HTTP [35]. DFBCIn hará peticiones GET al servidor VXMLS. Este devolverá un documento XML encapsulado en una respuesta HTTP. Un mensaje GET permite solicitar un documento dada una URL, en esta petición se puede incluir el nombre del documento a solicitar y un número indeterminado de argumentos. Por lo tanto, para permitir la comunicación entre DFBCIn y VXMLS será necesario definir las URL a las que DFBCIn deberá referirse cuando necesite solicitar información de VXMLS, o solicitar que VXMLS realice alguna operación. Las operaciones que VXMLS debe permitir realizar son: Creación de una nueva sesión de usuario. Destrucción de la sesión de usuario. Petición de la descripción de un determinado menú. Cambio de un parámetro de personalización. Cada una de estas acciones será una URL a la que se le pasarán los argumentos necesarios. VXMLS responderá con un documento XML que DFBCIn podrá interpretar para obtener el resultado esperado. Suponiendo que la URL que apunta al servidor VXMLS sea las peticiones HTTP para realizar las operaciones anteriores serán: Para solicitar una nueva sesión para el cliente settopbox que tiene como clave palabrasecreta, DFBCIn deberá hacer una petición GET a la URL: Para destruir la sesión: Para solicitar el menú main menu, suponiendo que no se necesiten argumentos adicionales para dicho menú, la URL a solicitar será la siguiente:

73 Diseño de DFBCIn 55 En caso de que la petición de menú necesite argumentos, por ejemplo el menú películas con el argumento filtro con valor nuevas, la URL será: Para cambiar el la propiedad language a es, VXMLS deberá proporcionar la URL: Diseño de DFBCIn División en subsistemas Durante el análisis, se establecieron unos aspectos que sería deseable que cumpliera el diseño de la aplicación DFBCIn (sección 3.4.4), para aislar los módulos conflictivos de los módulos estables, evitando que los problemas y riesgos derivados de las partes más complicadas del sistema se propaguen por toda la implementación. La aplicación DFBCIn se compone de tres módulos básicos: Módulo gráfico: Será el encargado de realizar las operaciones gráficas necesarias para comunicarse con el usuario. Como efecto colateral, debido a la utilización de DirectFB, también se encargará del control de la entrada. Esto es así ya que es deseable que se puedan utilizar distintos módulos gráficos (en forma de plugins) sin necesidad de recompilar el resto de la aplicación, incluso módulos gráficos que no utilicen DirectFB. Puesto que la utilización de DirectFB condiciona la forma en la que se realiza el control de la entrada, la implementación de la entrada deberá estar en este módulo, aunque en el diseño lógico se considerará un submódulo. Un diseño en el que el módulo de entrada fuera independiente del módulo gráfico sería más correcto teóricamente, pero en la práctica siempre estaría fuertemente acoplado al módulo gráfico. Módulo de comunicación con VXMLS 1 : Se compondrá de un parser y una implementación del protocolo HTTP. Para el resto del sistema será una caja negra a la que se le pueden solicitar los menús (y el resto de operaciones que puede realizar VXMLS) indicados por las acciones que lo requieran. 1 de aquí en adelante módulo VXMLS, para abreviar

74 56 Capítulo 4. Diseño Motor de la aplicación: Será el encargado de coordinar la actuación de los dos módulos anteriores y de ejecutar los objetos de la clase Action. VXMLS Libreria grafica graphics.h Motor Modulo VXMLS Figura 4.7: Módulos de DFBCIn El módulo gráfico se implementará como una biblioteca dinámica, de forma que se puedan intercambiar distintos módulos que cumplan la interfaz esperada sin necesidad de recompilar el sistema. Los otros dos módulos formarán el programa que se enlazará dinámicamente con el módulo gráfico seleccionado. La figura 4.7 representa al sistema final, funcionando junto con el sistema VXMLS Interacción entre módulos En la figura 4.8 se describe un ejemplo de interacción entre los distintos módulos del sistema 2. Se observa como el módulo gráfico actúa como fachada (patrón Facade [38]), aislando la entrada y la salida del resto del sistema, y como el módulo VXMLS actúa como adaptador de VXMLS (patrón Adapter [38]), traduciendo las peticiones del motor para que sean comprensibles para VXMLS y las repuestas de VXMLS para que sean comprensibles para el resto de la aplicación. El motor controla la ejecución de ambos módulos. El diagrama muestra la secuencia que sigue el sistema en su inicio y un par de ejemplos de reacción ante distintos eventos. Los sucesos relevantes son los siguientes: 1. El motor inicia su ejecución y solicita al módulo VXMLS que se inicialice. 2. El módulo VXMLS pide una nueva sesión al servidor VXMLS, cuando éste le confirma la operación devuelve el control al motor. 2 Las funciones y mensajes son una simplificación de las interfaces entre los módulos.

75 Diseño de DFBCIn 57 Modulo grafico Motor Modulo VXMLS VXMLS init() login ok init() getmenu(mainmenu) getmainmenu menu documento XML menu visual showmenu(menu) evento de usuario evento de entrada menu visual changeoption(newoption) evento de temporizacion setproperty(language, es) setlanguage(es) Figura 4.8: Interacción entre los módulos de DFBCIn 3. El motor inicializa el módulo gráfico. 4. El motor solicita al módulo VXMLS el objeto menu que representa el primer menú a mostrar al usuario. 5. El módulo VXMLS hace una petición HTTP a VXMLS solicitando la descripción del menú principal, recibe la respuesta de VXMLS y la transforma en el objeto Menu solicitado. 6. El motor le solicita al módulo gráfico que muestre el menú en la pantalla. 7. El usuario reacciona ante el menú y genera algún tipo de evento, por ejemplo pulsa una tecla que debería cambiar la opción seleccionada. 8. El módulo gráfico detecta este evento y se lo comunica al motor. 9. El motor obtiene el conjunto de acciones relacionadas con el evento notificado por el módulo gráfico y las ejecuta. 10. La acción que debería cambiar la opción provoca que el motor mande un mensaje al módulo gráfico para que muestre el cambio por pantalla. 11. El motor detecta un evento de temporización y ejecuta las acciones definidas para dicho evento. 12. Esta vez la acción ejecutada debe cambiar el lenguaje. Para ello, el motor solicita al módulo VXMLS que realice este cambio.

76 58 Capítulo 4. Diseño 13. El módulo VXMLS envía un mensaje HTTP a VXMLS solicitando el cambio de lenguaje a VXMLS, espera a la confirmación y comunica al motor el éxito o fracaso de la operación. Hay varios eventos que pueden provocar la ejecución de acciones por parte del motor, algunos de estos eventos son detectados por la biblioteca gráfica (los eventos provocados por la entrada del usuario o durante la reproducción de un vídeo) y otros son controlados por el motor (los eventos de temporización y la inicialización de menús). Durante la ejecución de las acciones, el motor utilizará el módulo gráfico y el módulo VXMLS para comunicarse con los agentes externos al sistema (el usuario y VXMLS). En resumen, el flujo de información entre los tres módulos de DFBCIn y los dos agentes externos (usuario y VXMLS) es como sigue: El usuario se comunica con el módulo gráfico mediante los dispositivos de entrada necesarios (por ejemplo el mando a distancia) y recibe información del mismo a través del televisor. El módulo gráfico controla estos dispositivos. El módulo gráfico envía eventos al motor para que éste ejecute las acciones pertinentes. El motor se comunica con el usuario provocando cambios en la interfaz utilizando el API ofrecido por el módulo gráfico. El motor utilizará otro API para solicitar al módulo VXMLS que realice las operaciones que requieran comunicación con el servidor VXMLS. El módulo VXMLS enviará las peticiones HTTP necesarias y traducirá la respuesta transformándola en objetos comprensibles por el motor de la aplicación (normalmente instancias de la clase Menu) Objetos comunes La clase Menu explicada en la sección deberá ser implementada en DFBCIn para permitir la comunicación entre los tres módulos que la componen. Para almacenar información sobre el estado de los objetos Menu almacenados por DFBCIn, el diseño general de clase Menu deberá ser ligeramente extendido. La aplicación necesita saber para cada menú, cuáles son las teclas que están vinculadas a qué acciones. Para ello se añade una nueva clase Key que será referenciada por la clase Menu.

77 Diseño de DFBCIn 59 Menu + majorversion: Int + minorversion: Int header: String time: Int Option text: String + execute() for all actions do action.execute end Key + draw() + key: String event: String + execute() initactions timeactions * actions ACTIONS EXECUTE NULL 1.. <<interface>> Action + execute() 0.. * Figura 4.9: Clase Menu en DFBCIn Para manejar información persistente se ha diseñado un pequeño sistema de propiedades que leerá y guardará la información de un fichero de texto. Este sistema permitirá a los distintos hilos de ejecución de la aplicación acceder concurrentemente al contenido del fichero y modificarlo en caso de que sea necesario. Los métodos exportados para el resto de la aplicación son tres: getpropertyvalue: Devuelve el valor de una propiedad con un nombre dado. setpropertyvalue: Cambia el valor de una determinada propiedad. saveproperties: Salva los datos almacenados en memoria en el disco. En los últimos incrementos, la mayoría de los parámetros de personalización pasan a ser almacenados por VXMLS, por lo que, finalmente, el sistema de propiedades solamente se utilizará para almacenar valores estáticos que no necesitan ser cambiados (el nombre y clave del Set Top Box, la dirección del servidor, etc). También se han diseñado dos clases para almacenar distintos tipos de información, la clase Stack (pila) y la clase Array. Ambas clases se pueden utilizar para guardar cualquier tipo de objeto Diseño del motor de la aplicación Objetivos El objetivo de este módulo es el de controlar el funcionamiento del resto de módulos del sistema y el de realizar las acciones especificadas por los objetos 3 La implementación de estas clases en C presenta ciertos problemas a la hora de compartir objetos y de liberar memoria como se verá en el capítulo dedicado a la implementación de DFBCIn

78 60 Capítulo 4. Diseño Stack + empty(): Boolean + push(data: Object) + pop(): Object + seetop(): Object Array + add(data: Object) + getdata(position: Int): Object + elements(): Integer + flush() Figura 4.10: Clases para el almacenamiento de datos Action que deban ser ejecutados. Este módulo contiene la implementación de la parte más estable del sistema, ya que no está en contacto con ningún agente exterior. Básicamente, deberá implementar el ciclo de ejecución y las estructuras de datos para mantener la información necesaria para la ejecución de las acciones recibidas. Con respecto a los objetos del dominio, a este módulo le corresponde la implementación de los objetos pertenecientes a la clase Action. Será el módulo encargado de realizar las operaciones convenientes para ejecutar las acciones Estructura interna En la figura 4.11 se puede ver el diseño interno de este módulo. Básicamente, tiene cinco componentes: el objeto principal, un objeto encargado de controlar la interfaz con el usuario, un objeto que ayudará a éste controlando los eventos de entrada, un objeto que se encargará de reproducir archivos de audio y las implementaciones de la interfaz Action. Main: El método main será el método a invocar para iniciar la ejecución de la aplicación. Interface: Un objeto de esta clase se encargará de controlar la comunicación con la biblioteca gráfica, realizando las operaciones necesarias para mostrar la interfaz del usuario correctamente. InterfaceInput: Un objeto de esta clase se encargará de comunicarle a Interface los eventos de entrada de usuario que detecte con ayuda de la biblioteca gráfica. Interface e InterfaceInput son una aplicación simplificada del patrón Observer [38]. InterfaceInput avisará a Interface cuando detecte un evento de entrada y lo almacenará hasta que Interface pueda atenderlo. Mp3Player: Un objeto de esta clase se encargará de reproducir ficheros de audio.

79 Diseño de DFBCIn 61 Modulo VXMLS Main + main() Recibe gupos de acciones de interface y para cada una de ellas ejecuta Action.execute Interface Action + execute() actualmenu: Menu <<interface>> + loadmenu(menu: Menu) + showmenu() + hidemenu() + unloadmenu() + loadvideo(video: String, endactions: array) + playvideo() + stopvideo() + resumevideo() + unloadvideo() + waitforactions(): Array + notifyinputevent() + notifyvideoend() + notifynewframe() Mp3Player path: String + load(path: String) + pausecontinue() Modulo Grafico interfaceinput.getinputkey() InterfaceInput inputkey: Key + getinputkey(): Key notify() interface.notifyinputevent() Figura 4.11: Clases del motor Action: Las diferentes implementaciones de esta interfaz podrán utilizar tanto el módulo VXMLS como el módulo gráfico para realizar las operaciones necesarias para la ejecución del método execute. La mayoría de las operaciones gráficas deberán hacerse utilizando el objeto Interface. Interface, InterfaceInput y Mp3Player son clases Singleton [38], la aplicación instanciará un único objeto de cada una de estas tres clases. La interacción entre los distintos objetos que componen este módulo se ha ejemplificado en la figura En ella se puede ver como Main notifica a Interface que está a la espera de nuevas acciones a ejecutar. Cuando InterfaceInput detecta un nuevo evento de entrada se lo hace saber a Interface y espera a que Interface puede consultar ese evento. Interface comprobará si hay un grupo de acciones relacionadas con el evento detectado y, de ser así, se las envía a Main para que las ejecute. Los métodos notifynewframe y notifyvideoend serán utilizados por el módulo gráfico para avisar a Interface de que hay un nuevo frame de vídeo listo para ser mostrado o de que el final del vídeo ha sido alcanzado. En este diagrama se han obviado las acciones de inicialización. También se debe tener en cuanta que no sólo los eventos de entrada pueden provocar la

80 62 Capítulo 4. Diseño Main Graphics create() create() Interface InterfaceInput waitforactions() Array notifyinputevent() getinputevent() InputKey evento de entrada Figura 4.12: Detección de eventos de entrada ejecución de acciones. Interface puede detectar otro tipo de eventos y devolver el grupo de acciones correspondiente al evento detectado Ciclo de ejecución de Main El ciclo de ejecución la aplicación (método main de la clase Main) se puede ver en la figura Inicializacion Menu Principal Esperando acciones Ejecutando acciones Figura 4.13: Ciclo de ejecución 1. En primer lugar deberá inicializar todos los subsistemas necesarios, es decir, el módulo gráfico y el módulo VXMLS. 2. El segundo paso consiste en obtener el objeto que representa al menú principal y pasárselo al módulo gráfico para que lo muestre por pantalla.

81 Diseño de DFBCIn Tras estos dos pasos iniciales el motor deberá esperar a que el objeto Interface entregue un bloque de acciones a ejecutar. 4. Una vez obtenidas las acciones, el motor pasará a ejecutarlas (para cada objeto de la clase Action recibido, se invocará su método execute). Cuando termine la ejecución del bloque completo volverá al estado de espera por un nuevo bloque de acciones. Es importante señalar que no se contempla la finalización del programa como un comportamiento normal. La aplicación sólo terminará en caso de que se produzca una situación anormal. Para el desarrollo, se ha definido una tecla EXIT que provoca la finalización de la aplicación generando una notificación de error artificialmente. La aplicación definitiva sólo debería terminar en caso de que se apague el Set Top Box, esto se considerará una situación excepcional y su control será idéntico al que se hace con los errores graves, que provocan la finalización de la aplicación Máquinas de estados de Interface e InterfaceInput En el diagrama de estados de la figura 4.14 se puede observar el proceso mediante el cual InterfaceInput notifica que ha detectado un nuevo evento de entrada. InterfaceInput bloquea la detección de eventos hasta que Interface recibe el evento detectado. Esto se podría evitar con una cola de eventos, pero eso se supone que lo hará la biblioteca gráfica en caso de que sea necesario. waitforactions() Reposo notifyinputevent()/ getinputkey() Sin Eventos nuevo evento/notify() getinputkey() notifyinputevent()/ getinputkey() waitforactions() EventoAlmacenado Acciones listas Esperando acciones Estados de InterfaceInput Estados de Interface Figura 4.14: Estados de InterfaceInput e Interface En el caso de los estados de Interface, todas las transiciones provocadas por notifyinputevent también podrán ser provocadas por notifyvideoend, pero para este caso, el módulo gráfico no cambia de estado tras la notificación de final de vídeo (no se puede producir un final de vídeo imprevisto antes de que Interface ejecute las acciones necesarias debidas al final notificado).

82 64 Capítulo 4. Diseño La máquina de estados de Interface es mucho más compleja que la mostrada en la figura 4.14, además los de estados referentes a las acciones a ejecutar, también debe mantener control sobre el estado del menú actual y sobre la reproducción de vídeo. Además los estados mostrados en esta figura son una pequeña simplificación: puede ser que la tecla detectada por InterfaceInput no tenga asociada ninguna acción. Por todo ello, es más sencillo representar sus transiciones como tres máquinas de estados concurrentes, aunque el estado real sea una combinación de los tres estados en los que se halle cada una de las submáquinas de estados. En la figura 4.15 se puede ver con más detalle la evolución de Interface durante su ciclo de ejecución. notifyvideoend()/getvideoactions() inicializacion de menu temporizacion waitforactions() Reposo tecla vinculada tecla EXEC Sin Menu Sin Video unload() notifyinputevent()/ getinputkey() tecla no vinculada notifyvideoend()/getvideoactions() inicializacion de menu temporizacion loadmenu(menu) Menu Cargado unloadmenu() load(video) Video Cargado waitforactions() play() Reposo Comprobacion de tecla Esperando acciones resumevideo() stopvideo() gotovideoposition() Reproduciendo tecla vinculada tecla EXEC notifyinputevent()/ getinputkey() tecla no vinculada Acciones listas Esperando Comprobacion de tecla Figura 4.15: Máquina de estados de Interface Como se puede ver, los estados referentes al vídeo y a los menús son más simples de lo que cabía suponer. El control real lo llevará el módulo gráfico. Interface simplemente necesita saber cuándo se está reproduciendo vídeo y cuándo no y cuándo tiene un menú cargado. El estado referente a si el menú es visible, si el vídeo esta parado, etc. será controlado por la biblioteca gráfica Ejecución de acciones La ejecución de ciertas acciones obliga a mantener algún tipo de estado durante el ciclo de ejecución del motor de la aplicación.

83 Diseño de DFBCIn 65 Las acciones NextMenuAction y PreviousMenuAction obligan a que se lleve un control de los menús anteriores al actual, esto se hará con una pila en la que se van almacenando los menús requeridos por NextMenuAction y de la que se van eliminando los menús descartados por PreviousMenuAction. La acción BindKeyAction necesita un mecanismo para almacenar las acciones vinculadas a las teclas para cada menú que se encuentre en la pila de menús. Para solucionar esto se ha ampliado la clase Menu como se explicó en la sección El resto de variables de estado (en la implementación actual el estado de un usuario sólo contempla las películas vistas y el lenguaje) serán mantenidas por el servidor VXMLS Reproducción de audio La reproducción de audio no influye en el resto del sistema, el reproductor comenzará a reproducir un fichero cuando sea cargado utilizando el método load y detendrá la reproducción cuando se invoque su método pausecontinue. La siguiente llamada a pausecontinue provocará que se reanude la reproducción. Para comenzar la reproducción de vídeo será necesario eliminar este objeto para que libere el dispositivo de audio, por lo tanto, load será un método de clase, que se encargará de instanciar el objeto correspondiente en caso de que aún no exista Diseño del módulo VXMLS Objetivos Este módulo deberá actuar como adaptador entre el motor y el servidor VXMLS, ocultando al resto del sistema la comunicación con VXMLS. En los primeros incrementos del sistema, este módulo no obtendrá las descripciones de los menús de VXMLS sino que utilizará medios de almacenamiento estáticos (en las primeras fases ficheros locales y en fases más avanzadas se comunicará con un servidor HTTP estático). En el diagrama de secuencia de la figura 4.8 muestra cómo interactúa este módulo con VXMLS para todas las operaciones enumeradas excepto para la liberación de recursos. Esta última operación consiste simplemente en el envío de un mensaje logout a VXMLS para que destruya la sesión creada en la inicialización del sistema.

84 66 Capítulo 4. Diseño Componentes del sistema La interfaz ofrecida por el módulo VXMLS al resto del sistema proporciona las siguientes operaciones. Inicialización: Esta operación deberá ser ejecutada una sola vez antes de realizar cualquier otra operación sobre este módulo. El módulo VXMLS solicitará una nueva sesión VXMLS y creará las estructuras de datos necesarias. Liberación de recursos: Provocará la liberación de la memoria ocupada por los datos internos de este módulo y la destrucción de la sesión creada para el usuario en VXMLS. Cambio de un valor de personalización: Los parámetros de personalización tienen un nombre y un valor, esta función permitirá solicitar a VXMLS que modifique el valor de un parámetro dado. Los únicos parámetros soportados en la implementación final son el usuario activo (cada Set Top Box tiene su cuenta en VXMLS y dentro de la misma puede mantener datos de varios usuarios) y el lenguaje a utilizar para el usuario activo. También se incluye dentro de este tipo de operación el hecho de marcar una película como vista. Solicitud de una descripción de un menú. Devuelve un objeto de la clase Menu describiendo el menú solicitado. Este módulo contiene dos componentes principales: el parser encargado de interpretar los documentos XML que VXMLS envía como respuesta a las peticiones de menús y una implementación parcial del protocolo HTTP que permita la comunicación con VXMLS. La interacción entre estos componentes se puede ver en la figura Motor Parser Modulo HTTP VXMLS getmenu() peticion de menu en un mensaje HTTP objeto menu setproperty() documento XML documento XML en un mensaje HTTP mensaje HTTP confirmacion documento XML confimacion XML en un mensaje HTTP Figura 4.16: Interacción entre los componentes del módulo VXMLS

85 Diseño de DFBCIn 67 Las operaciones login y logout son similares a la operación setproperty. Internamente, el módulo VXMLS se organizará como se puede ver en la figura Se compone de tres clases utilidad. VXMLSFacade: Fachada que proporcionará las operaciones especificadas por la interfaz al resto del sistema (patrón Facade [38]). Se encargará de componer la petición HTTP correcta, enviarla con ayuda de la clase HTTP e interpretar la respuesta de VXMLS utilizando los métodos de la clase Parser. HTTP: Controla la comunicación con el servidor HTTP. Se encargará de transmitir el mensaje GET para una URL de un servidor que esté escuchando HTTP en un determinado puerto y de devolver la respuesta del servidor como un flujo de datos. Parser: Interpreta los documentos XML obtenidos de VXMLS. VXMLS facade <<utility class>> + init + deinit() + getmenu(name:string, arguments:array) + setproperty(name:string, value:string) HTTP <<utility class>> Parser <<utility class>> + httpget(server:string, port:int, url:string): Stream + escapedenconding(string:string): String + parsemenu(menudocument: Document):Menu + parsevxmlsresponse(response: Document): Boolean Figura 4.17: Clases del módulo VXMLS Diseño del parser Es importante tener especial cuidado en el desarrollo de la clase Parser, deberá diseñarse de forma que sea fácil añadir código para interpretar las nuevas acciones que se vayan añadiendo al sistema. Como se vio en la sección 3.4.3, la biblioteca expat implementa un parser genérico en el que hay que definir ciertas funciones. Para los objetivos de este proyecto, las funciones que se deben implementar son las de apertura y cierre de etiquetas y la de sección de caracteres. Dichas funciones deben compartir algún objeto para almacenar información durante el proceso de interpretación del documento XML.

86 68 Capítulo 4. Diseño Para almacenar la información necesaria a lo largo del proceso de parsing se utilizará un objeto de la clase ParserData, que contiene una pila (ver la sección 4.5.3) y un objeto Menu que se irá construyendo a medida de que se disponga de la información necesaria. En la pila se almacenará objetos de la clase Context con la información necesaria para el tratamiento de las etiquetas abiertas hasta el momento. Normalmente, en caso de que sea necesario, se apilará un nuevo contexto durante la apertura de la etiqueta y se desapilará durante el cierre de la etiqueta. De esta forma, una etiqueta puede acceder a la información de todas sus etiquetas padre. El diseño de clases del parser puede verse en la figura Expat MenuParser parserdata: ParserData + parse(document: Stream): Menu ParserData + pushcontext(context: Context) + popcontext(): Context + seetopcontext(): Context unconpletemenu contextstack Menu Stack TagManager + starttag(tag: Tag, arguments: Array, parserdata: ParserData) + endtag(tag: Tag, parserdata: ParserData) + characterdata(tag: Tag, data:string, paserdata: ParserData) Context 0.. OptionContext + option: Option CharacterContext + text: String ActionContext + action: Action BindKeyContext + key: Key HeaderContext TextContext VersionContext + majorversion: Int + minorversion: Int Figura 4.18: Clases utilizadas para la construcción del parser para descripciones de menús La clase Context es abstracta para permitir la ampliación de los tipos de información almacenables en caso de que sea necesario. Por ejemplo, cuando se añadió la acción BindKey (ver la sección 4.2.3) fue necesario añadir una nueva estructura para almacenar información durante el proceso de parsing de las etiquetas que definen dicha acción. Con este diseño, simplemente hizo falta extender la clase Context y crear una nueva clase para la etiqueta específica. Las funciones de apertura y cierre de la etiqueta action deberán ser capaces de manejar las acciones como clases abstractas que son. Para ello, en la apertura de una etiqueta action se apilará un nuevo objeto de la clase ActionContext cuyo atributo action será una acción vacía. Las funciones que controlan las etiquetas

87 Diseño de DFBCIn 69 que pueden aparecer anidadas dentro de una etiqueta action deberán crear el objeto de una subclase Action concreta y colocarlo en el contexto apilado para la etiqueta action. El control de las acciones a realizar para la apertura y cierre de cada etiqueta lo hará la clase utilidad TagManager. La implementación de esta clase también deberá ser adaptada a medida que vayan apareciendo nuevas etiquetas a tratar. Aún así, la utilización de la pila de contextos permite que el código necesario para el tratamiento de las nuevas etiquetas que aparezcan para describir acciones no afecte al código ya existente: El código para manejar las etiquetas anidadas dentro de action solamente necesita tener en cuenta los datos que hay en la pila por encima del contexto colocado en la apertura de la etiqueta action. El código que maneja la etiqueta action espera que cuando se cierre esta etiqueta, el atributo action del contexto de la cima de la pila sea la acción completa, sin importar que implementación concreta de la interfaz Action sea. El código para manejar el resto de etiquetas no se ve afectado, ya que no hay datos referentes a las acciones en la pila. Normalmente, una etiqueta que pueda tener texto anidado colocará un contexto CharacterContext en la cima de la pila durante su apertura, La función characterdata escribirá el texto en dicho contexto y durante el cierre de la etiqueta se procesará dicho texto. Esto se hace así porque expat no asegura que el texto contenido por las etiquetas sea leído en un solo bloque, sino que podrá ser leído en varios bloques provocando varias llamadas a la función characterdata. El parser utilizado para las repuestas de VXMLS es mucho más sencillo y puede ser desarrollado directamente, sin necesidad de una pila Diseño del módulo HTTP Este módulo será el encargado de enviar peticiones GET HTTP [35] a un servidor y devolver su respuesta a través de un descriptor de fichero, de forma que pueda ser interpretada por el parser. El diseño de este módulo no presenta ninguna dificultad digna de mención, el proceso a seguir ante una llamada a la función httpget 4 para enviar una petición a un puerto de un servidor determinado será: 4 La sintaxis exacta para esta función en C es int httpget(const char *server, int port, const char *request, int filedes).

88 70 Capítulo 4. Diseño 1. Establecer una conexión TCP con el servidor en el puerto especificado. 2. Componer la cabecera HTTP a enviar al servidor. 3. Enviar dicha cabecera y esperar por la respuesta. 4. Interpretar la cabecera HTTP de la respuesta, tomar medidas en caso de que sea necesario (por ejemplo, almacenar las cookies) y escribir el contenido de la respuesta en el descriptor de fichero. 5. Cerrar el descriptor de fichero en cuanto se detecte el final del mensaje (para poder utilizar un pipe con el parser). La función escapedencoding se utilizará para codificar las cadenas de texto que forman la URL solicitada de acuerdo con las especificaciones de [42] Funciones de la fachada VXMLSFacade VXMLSFacade oculta la estructura interna de este módulo al resto del sistema. Para implementar las funciones que ofrece su API utilizará los dos submódulos comentados anteriormente y el subsistema de propiedades (ver 4.5.3). init: Durante la inicialización, VXMLSFacade obtendrá del sistema de propiedades el nombre y clave del Set Top Box, así como el servidor y puerto en el que está escuchando VXMLS. Con estos datos utilizará el módulo HTTP para enviar a VXMLS una petición de nueva sesión de usuario. Finalmente, utilizará el parser VXMLS para asegurarse de que VXMLS confirma la operación o para obtener el mensaje de error en caso contrario. deinit: Durante la destrucción del módulo VXMLS la fachada enviará un mensaje a VXMLS para que destruya la sesión VXMLS (obteniendo el servidor y puerto del sistema de propiedades y enviando el mensaje con ayuda del módulo HTTP como en el caso anterior). Interpretará la respuesta de VXMLS con el parser VXMLS. setproperty: Enviará un mensaje a VXMLS notificando el nuevo valor para la propiedad 5 de forma similar a como se explicó en los dos casos anteriores. getmenu: De nuevo enviará un mensaje solicitando un menú con ayuda del sistema de propiedades y el módulo HTTP. Interpretará la respuesta del módulo HTTP con ayuda del parser de menús y devolverá el objeto Menu correspondiente al menú solicitado. 5 estas propiedades las almacena el servidor, las propiedades locales las maneja el sistema de propiedades local.

89 Diseño de DFBCIn Diseño del módulo gráfico Objetivos La función de este módulo será la de controlar tanto los interfaces de salida como los de entrada. La inclusión del control de la entrada en este módulo es un efecto colateral de la utilización de DirectFB, como se explicó en la sección Asimismo como interfaz de salida no sólo se utilizará la pantalla, sino que también se controlará el dispositivo de audio durante la reproducción de vídeo. Por estos dos motivos, este módulo podría haberse llamado módulo de entrada/salida, pero el API que ofrece al resto del sistema solamente contiene operaciones para modificar los gráficos mostrados en pantalla y una función para obtener un evento de entrada. Este módulo será un componente intercambiable del sistema final, se podrán elegir diferentes implementaciones del mismo API sin necesidad de recompilar la aplicación. Se han desarrollado dos módulos gráficos distintos, uno de pruebas que utilizará la consola de texto para mostrar los menús y que mostrará mensajes en lugar de realizar operaciones tales como reproducir vídeo y el módulo gráfico de verdad con todas las operaciones necesarias para permitir la ejecución correcta de las acciones implementadas en el sistema. En las siguientes secciones se describirá el diseño que se ha seguido para la implementación completa utilizando DirectFB, en la sección se explicará brevemente qué objetos deberán cambiar para la implementación del módulo simplificado para las pruebas. El diseño de ambos módulos es idéntico, lo único que cambia es la implementación de los métodos Funciones del API El API que deberá implementar un componente que pretenda ser utilizado como módulo gráfico para DFBCIn deberá ofrecer las siguientes operaciones (el API formal se puede ver en el apéndice B): init y deinit: Se asegura que DFBCIn llamará una sola vez a la función init antes de llamar a cualquier otra función del API. También asegura que se llamará a la función deinit antes de terminar la ejecución y que no se llamará a ninguna otra función del API después de la llamada a deinit. loadmenu: Carga un objeto Menu en el módulo gráfico.

90 72 Capítulo 4. Diseño unloadmenu: Elimina el objeto Menu actual del módulo gráfico. setbox: Especifica si se debe dibujar una caja semitransparente rodeando al menú. loadvideo: De forma similar a loadmenu, establece el vídeo actual. playvideo: Inicia la reproducción del vídeo actual. stopvideo: Congela la reproducción de vídeo. resumevideo: Continúa con la reproducción de vídeo. getvideoposition: Devuelve la posición de vídeo actual. gotovideoposition: Posiciona el vídeo. blitvideo: Copia el frame actual en la pantalla. unloadvideo: Libera los recursos consumidos para la reproducción de vídeo. setnewframecallback: Establece un método que será invocado por el módulo gráfico cada vez que haya un nuevo frame disponible. setvideoendcallback: Establece el método a invocar por el módulo gráfico cuando se alcance el final del vídeo. flipscreen: Este será el método que deberá ser llamado por el motor de la aplicación para hacer visibles los cambios de estado hechos utilizando el resto de métodos del API. Cuando se invoque esta acción, el módulo gráfico deberá dibujar bien el fondo de pantalla, bien el último frame de vídeo disponible, y por encima el menú cargado en caso de que lo haya. testinput: Bloquea la ejecución hasta que haya un nuevo evento de entrada disponible. En caso de que ya se hubiera detectado un evento de entrada anterior a esta llamada, será devuelto ese evento sin bloquear la ejecución. Hay que tener en cuenta ciertas consideraciones adicionales a la hora de implementar un nuevo componente que respete este API: El objeto menú cargado con loadmenu pasa a estar compartido con el resto de la aplicación, por lo tanto, será necesario bloquearlo cuando se quiera acceder a su información. La operación loadmenu no hace el menú visible, es necesario llamar a flipscreen para ello; lo mismo ocurre con hidemenu.

91 Diseño de DFBCIn 73 Entre las llamadas a loadvideo y unloadvideo, las llamadas a flipscreen provocarán que se dibuje el frame actual como fondo Subsistemas del módulo En el diseño de este módulo se debe hacer especial hincapié en aislar el código conflictivo lo más posible, ya que este módulo implementa dos partes especialmente problemáticas del sistema: el control de la entrada de usuario y la utilización del hardware gráfico. El diagrama de clases de la figura 4.19 muestra la división que se ha hecho para aislar el código inestable en diferentes objetos. <<utility class>> GraphicsFacade Todos los metodos delegan en el objeto correspondiente VideoPlayer video: VideoObject + gotoposition(pos: Int) + load(video: String) + play() + stop() + unload() + videoblit() + getposition(): Int + setnewframecallback(callback: function) + setendcallback(callback: function) newframe() end() InterfaceDraw menu: Menu showbox: Bool + loadmenu(menu: Menu) + unloadmenu() + setbox(showbox: Bool) + flipbuffer() EventCatcher + testinput(): Key Hardware E/S DirectFB Figura 4.19: Clases utilizadas para la construcción módulo gráfico Como siempre, la estructura interna del módulo se oculta tras una aplicación del patrón Facade [38]. InterfaceDraw contiene el código encargado de dibujar los menús y el fondo en la pantalla. VideoPlayer contiene el código encargado de manejar los objetos de vídeo. También deberá realizar operaciones de dibujo en la pantalla. EventCatcher que transformará los eventos detectados en objetos del tipo Key. EventCatcher contiene el código dependiente del dispositivo de entrada, de esta forma InterfaceInput se mantiene independiente con respecto al sistema de control de entrada utilizado (ver la sección ).

92 74 Capítulo 4. Diseño El diseño de Interface, (ver la sección ) y VideoPlayer es una simplificación del patrón Observer [38], VideoPlayer deberá avisar a Interface cada vez que decodifique un nuevo frame de video o cuando el vídeo que se está reproduciendo finalice. La máquina de estados de VideoPlayer se puede ver en la figura Lo único destacable de este diagrama es que las operaciones de posicionamiento pueden provocar la finalización del vídeo, así como retroceder un vídeo ya finalizado. Sin Video unload() unload() load(video) Video Cargado play() Reproduciendo fin del video setposition() stop() resume() setposition() Finalizado Parado setposition() Figura 4.20: Máquina de estados de VideoPlayer La máquina de estados de InterfaceDraw debe contemplar los casos de tener o no un menú cargado y tener o no texto cargado Módulo gráfico basado en la consola de texto Para la ejecución de ciertas pruebas se ha desarrollado un módulo gráfico que utiliza la consola de texto para representar los menús. El resto de operaciones como la reproducción de vídeo o el cambio de buffer visible se representarán mediante mensajes de texto. Asimismo, este otro módulo gráfico sirve para validar el hecho de que se puedan intercambiar distintas implementaciones de este componente sin necesidad de recompilar el motor y el módulo VXMLS. El diagrama de clases para este sistema es el mismo que el mostrado en la figura 4.19, con la diferencia de que ninguna clase utiliza DirectFB. Las modificaciones que se introducen en este módulo son:

93 Diseño de VXMLS 75 InterfaceDraw: Mostrará el menú actual en la consola de texto. VideoPlayer: Todas los métodos (excepto los de notificación, que se dejan con implementación vacía) muestran un mensaje informando que se ha llamado a ese método, sin realizar ninguna otra operación. InterfaceInput: Los eventos de entrada se detectarán de forma rudimentaria utilizando funciones de la biblioteca stdio de C. En la figura 4.21 se puede ver el aspecto visual que presentan ambas implementaciones. Figura 4.21: Aspecto visual de las dos implementaciones del módulo gráfico 4.6. Diseño de VXMLS Introducción El diseño de la aplicación VXMLS se ha hecho siguiendo el patrón Model/View/Controller [43]. Este patrón permite separar el aspecto visual (vista) de los datos que refleja (modelo). La capa controlador se encarga de interpretar los eventos generados por el usuario y actuar en consecuencia, normalmente provocando cambios en el modelo (que serán reflejados por la vista). Para el caso de esta aplicación, el usuario será una instancia de la aplicación DFBCIn, por lo que la entrada será más controlable. La vista se encargará de generar documentos XML de acuerdo con el modelo y las peticiones del usuario. El modelo deberá ofrecer una interfaz para acceder y modificar la información persistente. En este proyecto se ha utilizado la base de datos Mnesia [40] perteneciente a la plataforma Erlang/OTP. El hecho de utilizar una base de datos

94 76 Capítulo 4. Diseño interna a la plataforma de programación utilizada simplifica la implementación de la capa modelo, ya que las funciones de la interfaz del modelo se podrán implementar directamente sin necesidad de incluir una subcapa para el acceso a una base de datos externa. Aún así, el modelo debe ser diseñado de forma que oculte la utilización de Mnesia, de forma que se pueda sustituir por otra base datos utilizando una subcapa de adaptación y un controlador para la nueva base de datos. Vista Controlador Modelo DFBCIn Modelo VXMLS Mnesia Datos persistentes Figura 4.22: Patrón Model/View/Controller en el diseño de VXMLS La aplicación VXMLS desarrollada tiene una funcionalidad muy básica, pero este diseño es igualmente válido para una aplicación más compleja Objetos del dominio La información que necesitará VXMLS para su funcionamiento se estructura de la forma descrita en la figura Para cada Set Top Box registrado se permite un cierto número de usuarios. Cada usuario tiene un lenguaje asociado y un conjunto de películas vistas. Las películas están asociadas a un único género y tienen cierta información que está almacenada en distintos idiomas. Los géneros tienen un nombre que también se almacena para los distintos idiomas. Para manejar las sesiones creadas para los diferentes Set Top Boxes, se utilizará un sistema de cookies, cada sesión se identificará con una única cookie que, a su vez, estará relacionada con un único Set Top Box. VXMLS también deberá manejar objetos de la clase Menu (ver figura 4.3). No será necesario implementar los métodos de la clase Menu ya que los objetos creados serán enviados a DFBCIn, que será el encargado de ejecutar los métodos necesarios. VXMLS simplemente se encargará de dar los valores correctos a los atributos de los objetos solicitados por DFBCIn, transformarlos en documentos

95 Diseño de VXMLS 77 1 n Set Top Box Usuario Lenguaje n Cookie Genero 1 n n Info Genero 1 n n 1 Pelicula n n Info Pelicula Figura 4.23: Objetos del dominio XML y enviarlos utilizando el protocolo HTTP. Para manejar la información persistente se utilizará una aplicación del patrón Value Object [44]. Este patrón permite encapsular varios datos relacionados en un único objeto, facilitando el intercambio de información entre las diferentes capas de la aplicación. Los objetos pertenecientes a la clase Menu explicada en la figura 4.3 serán definidos siguiendo el diseño mostrado en la figura Con este diseño, VXMLS mantendrá encapsulada la información necesaria para enviar la información sobre los menús a DFBCIn. Menu Timer majorversion: Int minorversion: Into header: String + getminorversion(): Int + getmajorversion(): Int + getheader(): String + gettimer(): Timer + getinitactions(): Array + getoptions(): Array + gettimer(): Timer + gettimer(): Timer 0..1 time: Int + gettime(): Int + getactions(): Array Option 0..* text: String + gettext(): String + getactions(): Array initactions 0..* 0..* 0..* <<interface>> Action 0..* 0..* endactions HideMenu ChangeOption NextMenu PreviousMenu ShowMenu SeekVideo PlayVideo value: Int mode: String + getvalue(): Int + getmode(): String name: String argument: Array + getname(): String + getstring(): Array depth: Int reinit: Bool + getdepth(): Int + getreinit(): Bool time: Int mode: String + gettime(): Int + getmode(): String file: String + getfile(): String + getendactions(): Array ReloadMenu HideText UnloadVideo SetProperty ShowText StopVideo ResumeVideo BindKey name: String value: String + getname(): String + getvalue(): String lines: Array + getlines(): Array key: String event: String + getkey(): String + getevent(): String + getactions(): Array Figura 4.24: Objetos valor utilizados para definir objetos Menu Los objetos valor necesarios para almacenar la información sobre los usuarios,

96 78 Capítulo 4. Diseño películas y lenguajes se puede ver en la figura SetTopBox id: String password: String currentuserid: String cookieid: String + getpassword(): String + getid(): String + getcookie(): Cookie + setcookie(cookie: Cookie) + getactiveuserid(): String + setactiveuser(userid: String) Cookie id: String stpbxid: String + getid(): String + getstpbx(): Set Top Box User 1..* name: String languageid: String + getname(): String + getlanguageid(): String + setlanguage(languageid: String) Movie 0..* id: String file: String year: Int genreid: String Shown Movies + getid(): String + getfile(): String + getinfo(lang: String): MovieInfo + getgenreid: String + getyear(): Int Language id: String name: String + getid(): String + getname(): String Genre id: String name: String languageid: String + getid(): String + getname(): String 1..* MovieInfo title: String synopsys: String + gettitle(): String + getsynopsys(): String TranslatedMovie + getmovie(): Movie + getmovieinfo(): MovieInfo Figura 4.25: Objetos valor utilizados por VXMLS La clase TranslatedMovie no representa a ningún objeto persistente, pero es útil para almacenar toda la información relativa a una película en un determinado idioma. La clase Genre representa la información referente a un determinado género traducida a un idioma concreto. Esta clase representa a los objetos del dominio Genero y Info Genero definidos en la figura Los objetos Genero no necesitan ser definidos ya que el único atributo que tienen es su propio identificador Modelo entidad-relación Para mantener los objetos persistentes en la base de datos se ha diseñado el modelo entidad-relación de la figura Las tablas necesarias para implementar este modelo serán ocultadas al resto de la aplicación utilizando los objetos valor explicados en la sección anterior Diseño de la capa modelo La capa modelo presentará una fachada (patrón Session Facade [44]) al resto del sistema. Esta fachada proporciona una interfaz simple a los clientes, ocultando la interacciones complejas ente los objetos del dominio. De esta forma se evita

97 Diseño de VXMLS 79 stpbx id cookie id Cookie 1:1 cookie id user name user name 0:1 1:1 1:1 1:n 1:1 Set Top Box User password 1:1 0:n stpbx id stpbx id language id movie id 0:n 0:n 0:n Language Shown Movie user name title lang name 1:1 Movie Info 1:1 movie id synopsys movie id genre id 0:n 1:n Movie 1:1 new year file language id 1:1 Genre Info language id 1:1 1:n 0:n Genre genre name genre id genre id Figura 4.26: Modelo entidad-relación exponer la estructura interna de la capa modelo al resto del sistema. El hecho de utilizar Mnesia [40] como base de datos elimina la necesidad de diseñar una capa de DAOs [44] para desacoplar los métodos de la fachada de la base de datos utilizada. Por lo tanto, el modelo de VXMLS se compondrá únicamente de una clase fachada que utilizará el API de Mnesia para acceder a los datos persistentes. Los métodos públicos que deberá ofrecer la fachada son: Obtener la contraseña de un determinado Set Top Box. Crear una nueva cookie y enlazarla a un Set Top Box. Eliminar una cookie (y desenlazarla del Set Top Box correspondiente). Obtener el identificador del Set Top Box enlazado a una cookie. Buscar todos los usuarios de un Set Top Box. Devolverá una lista de objetos User. Establecer el valor de una propiedad de personalización.

98 80 Capítulo 4. Diseño Obtener el lenguaje seleccionado por un determinado usuario. No devuelve el objeto Language en sí, sino su identificador (que es el identificador ISO del lenguaje). Buscar todos los lenguajes soportados por el sistema. Devuelve una lista de objetos Language. Buscar todos los géneros. Devuelve una lista de objetos Genre. Buscar todas las películas de un cierto género que ya han sido vistas por un determinado usuario. Devuelve una lista de objetos TranslatedMovie. Buscar las películas de un género que no han sido vistas por un usuario dado. Podrá devolver una lista con las películas nuevas (atributo new de la clase Movie) o con las viejas según se desee. Como para la operación anterior, la lista devuelta contendrá objetos TranslatedMovie Obtener la información sobre una película traducida a un cierto idioma. Devuelve un objeto TranslatedMovie. Marcar una película como vista. Una alternativa a este diseño sería utilizar una fachada con estado (Stateful Session Facade), pero la implementación de este patrón en Erlang es más complicado que el de una fachada sin estado (Stateless Session Facade). No se ha desarrollado ninguna aplicación de administración para manipular los contenidos de la base de datos. En caso de hacerse, dicha aplicación debería acceder a la misma base de datos que VXMLS pero a través de otra fachada que ofreciera operaciones de creación y eliminación de tablas, así como operaciones para añadir información a las tablas existentes. Para hacer las pruebas del sistema, estas operaciones se han codificado en capa modelo de VXMLS, pero no estarán presentes en el API para el resto de la aplicación. La única operación disponible para realizar labores de administración será initdb, que creará las tablas necesarias e insertará los datos especificados en un fichero de configuración. Esta operación no podrá ejecutarse con el sistema en funcionamiento Diseño de la vista y el controlador La capa vista se compone de una única clase encargada de componer los documentos XML a enviar como respuesta ante las peticiones de los clientes DFBCIn.

99 Diseño de VXMLS 81 El controlador deberá atender las peticiones del usuario, actuar sobre el modelo para obtener la información necesaria y realizar las modificaciones oportunas y, finalmente, utilizar las operaciones proporcionadas por la vista para enviar la respuesta al usuario. En la figura 4.27 se pueden ver las relaciones entre las distintas clases que conforman la vista y el controlador (todas las clases pertenecen al controlador excepto XMLUtil). VXMLS Facade VXMLS Model + login(env: Array, args: Array): String + logout(env: Array, args: Array): String + getmenu(env: Array, args: Array): String + setproperty(env: Array, args: Array): String Logger PropertiesManager Menu Dispatcher + login(env: Array, args: Array): String + logout(env: Array, args: Array): String + setproperty(env: Array, args: Array): String + getmenu(env: Array, args: Array): String <<create>> Lib MenuDocument <<interface>> + validateuser(args: Array): Cookie + validatecookie(env: Array): String + httpdocument(header: Array, content:string): String + httpdocument(content: String): String XMLUtil + menu2xml(menu: Menu): String + errorreport(message: String): String + okmessage(): String MainMenu + XMLDocument(clientId: String, user: User, languageid: String, arguments: Array): String... + XMLDocument(clientId: String, user: User, languageid: String, arguments: Array): String Map + getvalue(key: String): String 1..* Language Server + getmessage(langid: String, messageid: String): String MenuComposer + compose(elements: Array): Menu + option(text: String, actions: Array): Option + timer(time: Int, data: Object): Timer + action(type: String, data: Object): Action elements contiene los distintos subobjetos que forman el menu tales como los objetos Option, un objeto Timer y los objetos Action con las acciones de inicializacion Figura 4.27: Clases de la vista y el controlador de VXMLS La clase VXMLSFacade es una clase utilidad que resulta de la aplicación del patrón Facade [38]. Será la interfaz de entrada al controlador que utilizará Inets [39] para solicitar que se realicen las operaciones correspondientes a una determinada URL (ver la sección 4.4). El resto de clases realizarán las siguientes funciones: Logger: Clase utilidad que se encargará de atender las URLs de petición de login/logout. Los argumentos que recibe son env con los campos de la cabecera HTTP de la petición hecha por el cliente y args con los argumentos pasados en la URL. En el caso de petición de login, deberá obtener los argumentos client y passwd de la URL y utilizar la clase Lib para comprobar que son correctos, en caso de que así sea, utilizará el método httpdocument para enviar un mensaje confirmando la operación y establecer la cookie devuelta por validateuser. Para realizar la operación de

100 82 Capítulo 4. Diseño logout, utilizará la clase Lib para comprobar la validez de la sesión, el modelo para eliminar la cookie almacenada en la base de datos para identificar la sesión que se estaba manteniendo para el usuario y, finalmente, de nuevo la clase Lib para crear el mensaje HTTP de respuesta con un campo que anula la cookie almacenada por el cliente. Para obtener el contenido de los mensajes a devolver utilizará la clase XMLUtil. PropertiesManager: Al igual que la clase anterior, atenderá las peticiones a la URL utilizada para cambiar los valores de personalización. Extraerá los argumentos name y value y utilizará PropertiesManager para realizar los cambios necesarios. Para identificar el usuario utilizará Lib para validar la cookie que deberá encontrarse entre los campos de la cabecera HTTP descritos por env. MenuDispatcher: Como las clases anteriores, atenderá las peticiones a la URL utilizada para solicitar un menú, comprobando la sesión del usuario utilizando la cookie. Obtendrá el menú a generar del argumento menu de la URL, después instanciará un objeto perteneciente a la subclase de MenuDocument correspondiente e invocará el método xmldocument para conseguir la descripción XML del menú solicitado. Esta descripción será transformada en un mensaje HTTP utilizando Lib. XMLDocument: Esta interfaz define los objetos que serán los encargados de crear los objetos Menu correspondientes a cada uno de los menús que pueden ser solicitados por DFBCIn. En la figura 4.27 sólo se muestra Main- Menu, que será la clase que describe el objeto que genera el menú principal, pero el resto de implementaciones se relacionan de forma idéntica con el resto de clases del sistema. Básicamente, lo que harán estos objetos cuando se invoque el método xmldocument será: 1. Solicitar a LanguageServer los mensajes necesarios, traducidos al lenguaje especificado por el argumento languageid. 2. Obtener la información necesaria utilizando el API expuesto por la capa modelo. 3. Crear un nuevo objeto Menu utilizando la clase MenuComposer. 4. Transformar el objeto Menu creado en un documento XML utilizando la clase XMLUtil. Lib: Clase utilidad que realizará ciertas operaciones misceláneas para la comprobación y creación de sesiones (validateuser y validatecookie) y para la creación de documentos HTTP (las dos variantes de httpdocument).

101 Diseño de VXMLS 83 También tendrá operaciones para realizar otras operaciones poco importantes, como pueden ser las transformaciones entre distintos tipos utilizados por la aplicación que, han sido omitidas para simplificar el diagrama. XMLUtil: Clase utilidad para generar documentos XML. Como se vio en apartados anteriores, algunas implementaciones de la interfaz Action son una aplicación del patrón Composite [38]. Dadas las características de los documentos XML es fácil transformar un compuesto en un documento utilizando una aproximación al patrón Visitor [38]. Por ejemplo, el pseudocódigo para transformar una acción playvideoaction en una etiqueta XML action con el contenido correspondiente sería: render(action: PlayVideoAction) { print("<action>") print(" <playvideo file=", action.file>) foreach(aux = action.endactions) { render(aux) } print(" </playvideo>") print("</action>") } XMLUtil visita cada componente del objeto Menu y lo transforma en una parte del documento XML que lo describe. No es una aplicación pura del patrón Visitor ya que la estructura interna de los objetos de la clase Menu debe ser conocida por el el visitante, pero es más fácil trasladar este diseño a una implementación en Erlang que el diseño propuesto en [38], en el que la clase visitada debe proporcionar un método que acepte la visita. La generación de los mensajes de error o de confirmación no presenta ningún problema ya que son documentos XML muy sencillos y con definiciones no recursivas. MenuComposer: Clase utilidad que proporciona las operaciones necesarias para componer objetos Menu. Es una aplicación del patrón Builder [38], las implementaciones de MenuDocument actúan como directores y MenuComposer como constructor. LanguageServer: Es una aplicación del patrón Singleton [38]. Controlará un conjunto de mapas en los que estarán almacenadas las traducciones de los diferentes mensajes visuales a los idiomas soportados por la aplicación. Las diferentes traducciones se cargarán de ficheros planos en los que se asociarán las claves identificadoras para cada mensaje con la cadena a mostrar para ese identificador.

102

103 Capítulo 5 Implementación de DFBCIn Índice General 5.1. Introducción Estándares de codificación Nombres Objetos Control de errores Control de concurrencia Tipos de datos de uso general Pilas Arrays La clase Menu La clase Option La clase Key La interfaz Action Introducción Tipos de datos Funciones Cómo instanciar una acción? Cómo añadir una nueva acción? Implementación del motor de la aplicación Main Interface

104 86 Capítulo 5. Implementación de DFBCIn InterfaceInput Mp3Player Implementación del módulo VXMLS Módulo HTTP Parser VXMLS Parser para los documentos menu Implementación de la fachada VXMLS Implementación del Módulo gráfico Introducción Estructuración del código La fachada graphics.c La inicialización de DirectFB Control de eventos de entrada Impresión de menús y texto Reproducción de vídeo Módulo de pruebas Sistema de propiedades Etapas de codificación Desarrollo del núcleo de la aplicación Reproducción básica de vídeo Pruebas en el Set Top Box Varias mejoras Comunicación HTTP Integración con VXMLS Integración con VoDKA Reproductor Mp3 y acciones de texto Introducción La implementación en C de un diseño orientado a objetos supone ciertas dificultades. C es un lenguaje imperativo de bajo nivel, la gestión de memoria, de errores y de concurrencia se debe hacer de forma explícita. Además, el concepto

105 Estándares de codificación 87 de objeto debe ser simulado de alguna forma, combinando estructuras de datos con funciones. Como norma general, la implementación de un objeto consistirá en un módulo en el que se definirán las estructuras de datos necesarias para almacenar la información relevante para cada objeto instanciado y las funciones que operarán sobre dichas estructuras de datos. En la sección 5.2 se explica con más detalle la estructura de estos módulos. Como se ha dicho en la fase de análisis, el ciclo de vida de DFBCIn seguirá el paradigma incremental. En la primera iteración se desarrollará un sistema que aporte la funcionalidad más básica. Una vez hecho esto, se irán añadiendo posibilidades hasta obtener el sistema final. A lo largo de este capítulo se explica la implementación del sistema final, en la sección 5.14 se explican los pasos que se dieron hasta alcanzar esta implementación Estándares de codificación Nombres Tanto los nombres como el contenido de los comentarios están escritos en inglés para facilitar la lectura del código a cualquier persona. Para conseguir un espacio de nombres suficientemente homogéneo y facilitar la compresión del código, se seguirán una serie de reglas a la hora de elegir los nombres de las funciones, tipos de datos y variables utilizadas. Los nombres compuestos estarán formados por las palabras concatenadas, marcando el principio de la cada palabra con una letra mayúscula: nombre- Compuesto. Los nombres de los Tipos de datos comenzarán con mayúsculas: Nombre- DeTipoDeDato. Las variables y funciones comenzarán con minúsculas: nombredevariable y nombredefunción(). Las funciones de creación (reserva de memoria) para un determinado tipo de dato TipoDeDato se llamarán newtipodedato.

106 88 Capítulo 5. Implementación de DFBCIn Las funciones de liberación de memoria para el tipo de dato TipoDeDato se llamarán freetipodedato. En caso que se lleve un control de referencias para una clase NombreDeClase cuyos objetos puedan ser compartidos y liberados por diferentes módulos de la aplicación, la memoria necesaria para el tipo de datos que representa los argumentos del objeto (ver sección 5.2.2) se manejará con las funciones newnombredeclase, addnombredeclasereference y releasenombredeclase. addnombredeclasereference se utilizará para señalar que hay una nueva referencia al objeto y releasenombredeclase para indicar que una referencia ya no va a seguir siendo utilizada. Cuando la última referencia deje de ser utilizada se liberará la memoria reservada para los datos del objeto en cuestión. En algunos casos es necesario exportar funciones que van a ser utilizadas por macros que oculten ciertos aspectos, o que van a ser utilizadas solamente como callbacks, existiendo otra función o macro que será utilizada en la mayoría de los casos para cumplimentar el objetivo al que está orientado dicha función. En estos casos la función se llamará nombredefunción, y la macro o función de uso general que utilice dicha función será llamada nombredefunción. Los tipos de datos suelen ser punteros a estructuras. El nombre de la estructura es irrelevante para la aplicación, excepto en el momento en el que se necesita reservar la memoria para dicha estructura. El nombre de la estructura de datos a la que apunta un tipo PunteroAEstructura será PunteroAEstructura. las funciones exportadas por un módulo que implemente una clase utilidad (ver sección 5.2.2) Módulo se llamarán módulofunción1, módulofunción2,... En caso de que un módulo Módulo necesite ser inicializado antes de ser utilizado, deberá definir las funciones móduloinit y módulodeinit para las labores de inicialización y liberación del módulo. Las funciones que operan sobre un tipo de datos TipoDeDatos tendrán el nombre del tipo de datos como parte de su nombre compuesto, por ejemplo operaciónsobretipodedatos. Los nombres de las macros se escribirán en mayúsculas, con barras bajas como separadoras entre las palabras: NOMBRE DE MACRO.

107 Estándares de codificación 89 los nombres de los ficheros fuente estarán en minúsculas y utilizarán un guión como separador de palabras en caso de que sea necesario: nombre-defichero.c, nombre-de-fichero.h Objetos La implementación de una determinada clase del diseño se hará dependiendo de si la clase es una clase utilidad, una clase que define un objeto Singleton [38] o una clase que define objetos que van a ser compartidos por diferentes módulos del programa. Una clase utilidad, por ejemplo ClaseUtilidad, será implementada creando un módulo ClaseUtilidad formado por el fichero clase-utilidad.c y la cabecera clase-utilidad.h. Las funciones exportadas en clase-utilidad.h deberán tener nombres que comiencen por claseutilidad, para facilitar la lectura del código (claseutilidadnombre, sería equivalente a una llamada al método nombre de la clase ClaseUtilidad en un lenguaje orientado a objetos). Los objetos Singleton serán implementados de forma similar a una clase utilidad, pero normalmente será necesario que el código que se encargue de simular su comportamiento esté en un nuevo hilo de ejecución. En la sección 5.4 se explica como se hará el control de los módulos que generan nuevos hilos de ejecución. La implementación de los objetos que vayan a ser compartidos entre diferentes módulos de la aplicación dependerá de si es necesario llevar las referencias del objeto para poder liberar la memoria o no. En ambos casos, el objeto a compartir se codificará como un tipo de dato que será un puntero a una estructura en la que se almacenará la información necesaria sobre el objeto en cuestión (puede ser necesario que dicha estructura también contenga algún semáforo o similar para controlar el acceso concurrente a sus contenidos) y una serie de funciones que simulen los métodos definidos por la clase a la que pertenece el objeto que estamos tratando. A estas funciones será necesario pasarles la estructura que contiene los datos del objeto. Por ejemplo si se quiere ejecutar el método objetocompartido.método, la línea de código será métodoobjetocompartido(objetocompartido,...). El constructor del objeto será la función newnombredeclase explicada en la sección En caso de que sea necesario llevar un control de las referencias existentes al

108 90 Capítulo 5. Implementación de DFBCIn objeto, para poder liberar su memoria, será necesario añadir un campo a la estructura de datos que contiene los atributos del objeto para contar dichas referencias. Para ello se definirá la función addnombredeclasereference que deberá ser llamada por cada nuevo módulo que vaya a mantener una referencia al objeto. La función releasenombredeclase liberará una referencia. La memoria reservada para mantener la información necesaria sobre el objeto será liberada cuando el contador de referencias llegue a cero. Las llamadas a releasenombredeclase deben ser sincronizadas para evitar problemas de concurrencia en caso de que varios hilos intenten ejecutar esta función simultáneamente, lo que podría dejar la memoria sin liberar. No es necesario sincronizar addnombredeclasereference porque se supone que se está accediendo de forma segura al objeto que se quiere referenciar en el momento en el que se añade dicha referencia, es decir, no hay peligro de que se haga una llamada releasenombredeclase que vaya a liberar la memoria ocupada por el objeto durante la ejecución de addnombredeclasereference, puesto que la referencia debe ser añadida en un hilo que ya mantenga su propia referencia Control de errores El estado de error de la aplicación se controla con la función setapperror, con la que se puede establecer el error que se ha detectado y el fichero y la línea en la que se ha producido. Como se explicó en la sección 5.2.1, un nombre que empieza por el caracter no debe ser utilizado directamente, esta función se exporta para que pueda ser utilizada por las macros que se definen para realizar el control de errores a lo largo de la aplicación. Los errores detectados se clasificarán según un tipo que está definido por la enumeración AppError. Se define una variable global de este tipo que será manipulada por las funciones exportadas por el módulo errors (estas funciones están declaradas en el fichero errors.h). Esta variable puede tomar uno de los siguientes valores : NO ERROR: No se ha detectado ningún error. MULTIPLE ERROR: Se ha llamado más de una vez a setapperror. NO MEMORY : No hay suficiente memoria. INVALID OPERATION : Se ha intentado realizar una operación no permitida.

109 Control de errores 91 PARSER ERROR: Error durante el proceso de interpretación de un documento de texto. IMPLEMENTATION ERROR: Se ha alcanzado una sección del código que no debería ser alcanzada. Se trata de un error en la implementación. VERSION ERROR: Se ha recibido un documento con una versión mayor a la que se puede manejar. EXTERNAL ERROR: Fallo en algo ajeno a la implementación (por ejemplo, fallo en una llamada al sistema). BAD FILE FORMAT : Un fichero no cumple la estructura que se esperaba. LOST PROPERTY : No se puede encontrar el valor de una propiedad obligatoria. DOWNLOAD ERROR: Fallo en la descarga de un fichero. VXMLS ERROR: Fallo en el servidor VXMLS. MPG123 ERROR: Fallo en el reproductor de mp3. Las funciones exportadas para permitir el control de errores durante la ejecución de la aplicación son: void seterrormessage(const char *message): Se utiliza para establecer un mensaje explicativo que será escrito por printapperror junto con la descripción genérica para el estado de error en el que se haya la aplicación. AppError getapperror(void): Devuelve el estado de error actual. void unsetapperror(void): Establece NO ERROR como estado de error. void printapperror(void): Escribe un mensaje explicativo en el descriptor de error estándar. short existserror(void): Devuelve 0 en caso de que el estado de error sea NO ERROR y un número distinto de 0 en otro caso. Para la aplicación desarrollada, el comportamiento que se seguirá en caso de se produzca una situación excepcional será establecer el error correspondiente y finalizar la ejecución lo antes posible, haciendo una llamada a printapperror antes de terminar para notificar las causas del fallo. Para ello, en errors.h se define la macro DFBCIN FATAL, que provoca la finalización inminente de la aplicación en un estado de error dado. Es posible llamar a seterrormessage antes para añadir información al mensaje mostrado en la finalización de la aplicación.

110 92 Capítulo 5. Implementación de DFBCIn #define DFBCIN_FATAL(error) \ { \ _setapperror(error, LINE, FILE ); \ printapperror(); \ unsetapperror(); \ exit(exit_failure); \ } También hay algunas funciones que pueden detectar errores durante su ejecución, pero que no pueden decidir si dicho error es lo suficientemente grave como para finalizar la ejecución o puede ser solventado de alguna otra forma. Estas funciones deberán devolver una variable de tipo AppError. En caso de que una llamada a una de estas funciones deba devolver un valor siempre correcto, la función que realiza la llamada puede utilizar la macro DFBCIN CHECK que terminará la ejecución en caso de que la función llamada devuelva un valor indicando un error. #define DFBCIN_CHECK(x...) \ { \ int err; \ \ err = (x); \ if (err!= NO_ERROR) { \ _setapperror(err, LINE, FILE ); \ printapperror(); \ unsetapperror(); \ exit(exit_failure); \ } \ } 5.4. Control de concurrencia En la sección 5.2.2, se comentó que para codificar los objetos de algunas de las clases del diseño sería necesario añadir nuevos hilos de ejecución. La programación multi-hilo en un lenguaje como C debe hacerse cuidadosamente, ya que posibilita la aparición de problemas muy difíciles de depurar. La implementación de aquellos objetos que tengan un ciclo de ejecución propio se hará en dos ficheros, el fichero fuente y la cabecera con las funciones exportadas. Para explicar cómo se estructurará el código que implementa este tipo de objetos se utilizará como ejemplo una clase ficticia Singleton, que se codificará en

111 Control de concurrencia 93 los ficheros singleton.c y singleton.h. En singleton.h se exportarán las funciones que serán accesibles para el resto de la aplicación: singletonmethod, singletonmethod2, etc. Entre estas funciones serán necesarias las funciones singletoninit y singletondeinit para permitir la creación y la destrucción del objeto. En el fichero singleton.c se definirán las funciones y estructuras de datos locales. En este caso, será necesaria una estructura de datos en la que mantener los datos referentes al estado del objeto y los semáforos que se utilizarán para el control de concurrencia. Será necesario definir al menos: Un tipo de datos SingletonState que describa el estado interno del objeto que se está implementando. Una variable global (pero no accesible desde fuera de este módulo) singletonstate de tipo SingletonState que contenga el estado interno del objeto. Un semáforo singletonmutex para controlar el acceso concurrente a singletonstate y que posibilite el control de la ejecución del nuevo hilo utilizando una condición singletoncond. Una función singetonthread que contenga el código necesario para que el objeto creado se comporte como se espera, de acuerdo con las especificaciones hechas en el diseño. La función singletoninit deberá crear la variable singletonstate y lanzar el nuevo hilo de ejecución, que estará implementado por la función singletonthread. La función singletonthread consistirá en un bucle que se ejecutará con el semáforo singletonmutex cerrado. El cuerpo del bucle realizará las acciones necesarias de acuerdo con el estado del objeto. En algún momento, la ejecución deberá ser detenida en la condición singletoncond. En este momento se liberará el semáforo para permitir a las funciones exportadas modificar el estado del objeto para variar su comportamiento. Las funciones exportadas en singleton.h no realizarán el trabajo solicitado por si mismas, sino que accederán a singletonstate, siempre después de haber cerrado el semáforo singletonmutex, modificarán el estado para que el hilo de ejecución del objeto sepa las acciones que tiene que realizar y despertarán la ejecución del hilo singletonthread que debería estar parado en la condición, para que compruebe de nuevo el estado y actúe en consecuencia. De esta forma, el

112 94 Capítulo 5. Implementación de DFBCIn ciclo de ejecución del objeto es concurrente con la ejecución del hilo principal del programa, pero los accesos a sus datos privados se mantienen sincronizados, ya que las funciones exportadas para la aplicación sólo pueden modificar del estado del objeto en un punto controlado. En caso de que el ciclo de ejecución del objeto no pueda ser detenido, se deberá codificar un punto en el que se libere el semáforo y se de paso a un nuevo proceso (utilizando las funciones del planificador) para permitir que las funciones exportadas puedan cambiar el estado interno del objeto: STATE_UNLOCK; sched_yield(); STATE_LOCK; 5.5. Tipos de datos de uso general Pilas Las pilas serán utilizadas para almacenar la información necesaria durante el proceso de interpretación de los ficheros XML que describen los menús de la interfaz y para almacenar los objetos Menu que se van cargando a medida que el usuario profundiza en la estructura de menús definida. Las pilas no necesitarán ser compartidas entre distintos módulos del sistema, por lo que no será necesario implementar el mecanismo de referencias. Para implementar la clase Stack (que representará a una pila de contenido genérico) se definirá un tipo de dato abstracto Stack y una serie de funciones que operen sobre él. El tipo Stack está completamente encapsulado, el resto de módulos del sistema no tendrán acceso a su estructura interna. El API exportado para la manipulación de pilas se compone de las siguientes operaciones: Stack newstack(void): Crea una nueva pila. short isemptystack(stack stack): Devuelve un número distinto de cero en caso de que la pila esté vacía. void pushstack(stack stack, void *data): Añade un nuevo dato a la cima de la pila.

113 Tipos de datos de uso general 95 void freestack(stack stack): Libera la memoria ocupada por la pila. La pila debe estar vacía para que se pueda realizar esta operación, en otro caso la aplicación terminará debido a un error INVALID OPERATION. void *popstack(stack stack): Devuelve el dato de la cima de la pila y lo borra de la misma. void *seestacktop(stack stack): Devuelve el dato de la cima de la pila, pero no lo borra de la misma Arrays Los arrays se utilizarán para almacenar una cantidad indeterminada de datos de forma que puedan ser compartidos entre distintos módulos del sistema. En la aplicación, la utilización de los arrays consistirá en crearlos, añadir un cierto número de elementos y, una vez añadidos todos los datos necesarios, transmitirlos a los módulos que los necesiten para que realicen operaciones sobre los datos almacenados. No será necesario borrar datos ya existentes o añadir nuevos datos a un array que ya ha sido compartido. La implementación de los arrays utilizará el sistema de referencias que se describió en la sección Para posibilitar la liberación de toda la memoria ocupada por un array (incluida la memoria que ocupan sus datos), en la función de creación del array se deberá especificar una función que sea capaz de liberar la memoria del tipo de datos que se vaya a almacenar en el array creado. Con estos dos mecanismos, un array con información puede ser compartido por varios módulos y puede ser fácilmente liberado cuando dichos módulos dejen de utilizarlo. Al igual que las pilas, los arrays se implementan utilizando un tipo abstracto de datos completamente encapsulado y un cierto número de funciones para operar sobre él. El API para manipular arrays es: Array newarray(freedatafunc 1 freefunc): Crea un nuevo array en el que se almacenará un cierto tipo de datos. freefunc será una función capaz de liberar la memoria ocupada por una variable del tipo de datos almacenado. 1 el tipo FreeDataFunc se define como void (*FreeDataFunc) (void *data)

114 96 Capítulo 5. Implementación de DFBCIn void releasearray(array array): Se utiliza para señalar que se va a dejar de utilizar el array, eliminando una de las referencias al mismo. Cuando se libera un array de forma que ya no queden referencias al mismo se libera también la memoria ocupada por array, incluyendo la memoria ocupada por todos los elementos almacenados. void flusharray(array array): Vacía el array liberando la memoria ocupada por todos los datos almacenados en el mismo. unsigned numarrayelements(array array): Devuelve el número de elementos almacenados en el array. void addarray(array array, void *data): Añade un nuevo elemento al final del array. void *getarraydata(array array, unsigned nth): Devuelve el elemento almacenado en la posición nth del array. El primer elemento se almacena en la posición 0. void addarrayreference(array array): Indica que hay un nuevo módulo utilizando el array añadiendo una nueva referencia al mismo. La implementación que se ha hecho de los arrays sólo comprueba la sincronización de las llamadas a releasearray, para evitar que se produzcan dos llamadas concurrentes con el riesgo de que quede la memoria sin liberar. El resto de funciones no están sincronizadas. Esta implementación no contempla la posibilidad de que varios módulos intenten añadir datos de forma concurrente La clase Menu Los objetos de la case Menu (ver sección 4.5.3) serán compartidos por varios módulos, pero la creación y destrucción de estos objetos no necesita ser controlada con el sistema de referencias. Los objetos Menu sólo podrán ser creados por el módulo VXMLS, y serán almacenados en una pila global, de forma que siempre esté accesible el menú mas recientemente utilizado. La destrucción de estos objetos se hará a medida que se desapilen. De esto se encargarán algunas de las diferentes acciones (en el sentido de instancias de Action) implementadas. Por todo ello, el hecho de que los objetos de la clase Menu vayan a ser compartidos no complica su creación y destrucción, pero sí será necesario añadir algún sistema para evitar escrituras concurrentes. Por lo tanto, el tipo de datos que contendrá los atributos de los objetos de la clase Menu también deberá tener

115 La clase Menu 97 asociado un semáforo que deberá ser bloqueado antes de acceder a sus contenidos. El tipo Menu definido no será un tipo completamente encapsulado como en el caso de los arrays o de las pilas. En este caso el resto de la aplicación deberá conocer la estructura interna del tipo Menu para poder modificar su contenido. Una variable de tipo Menu será un puntero a una estructura con los siguientes campos: short majorversion, minorversion: Indican la versión del esquema de menú utilizado, en caso de que DFBCIn reciba un menú con una versión mayor a la soportada deberá actualizarse 2. char header[]: Título a mostrar para el menú. Array options: Sostiene la agregación de objetos Option. int time: Tiempo que debe pasar sin que se reciba un evento de entrada para que se disparen las acciones de temporización, si es -1 se supone que la espera es infinita (no hay acciones de temporización). Array timeactions: Conjunto de acciones a ejecutar en caso de que termine la temporización. Array initactions: Conjunto de acciones a ejecutar cuando se cargue el menú por primera vez. short currentposition: Opción actualmente seleccionada. Key keys[]: Conjunto de objetos Key utilizados para almacenar la información sobre las acciones a realizar en caso de que se detecte un determinado evento de entrada (ver sección 5.8). char name[]: Nombre con el que fue solicitado el menú a VXMLS. Array arguments: Lista con los argumentos que se utilizaron para solicitar este menú a VXMLS. pthread mutex t mutex: Semáforo utilizado para la sincronización de los accesos concurrentes a los contenidos de esta estructura. Las funciones exportadas para manejar este tipo de datos son sólo las de creación, destrucción, bloqueo y desbloqueo, ya que el resto de operaciones se deberán hacer accediendo directamente a los contenidos de la estructura. 2 Esta característica aún no está implementada, es una línea de trabajo futura

116 98 Capítulo 5. Implementación de DFBCIn Menu newmenu(void): Devuelve una variable de tipo Menu ya inicializada (con memoria reservada tanto para la estructura de datos como para los arrays que contiene). void lockmenu(menu menu): Bloquea menu para evitar el acceso concurrente. void unlockmenu(menu menu): Desbloquea menu. void freemenu(menu menu): Libera la memoria ocupada por menu. Nótese que si a alguno de los arrays que contiene menu le fueron añadidas nuevas referencias éste no será liberado durante este proceso. De esta forma se pueden preservar acciones a ejecutar aunque se libere el menú que las contiene La clase Option Los objetos de la clase Option no serán compartidos directamente, sino que serán compartidos a través del menú que los contiene. Además, el acceso concurrente a sus contenidos siempre será a través del tipo Menu (de hecho, en el diseño se especificó que los objetos de la clase Option tienen una relación de composición con la clase Menu, ver la sección 4.5.3). Se supone que los accesos a una variable de tipo Menu siempre serán sincronizados, por lo que no será necesario tomar ninguna medida adicional para controlar los accesos a este tipo de objetos. La implementación de este tipo de objetos no presenta ningún tipo de complicación. Como en casos anteriores, se definirá un tipo de datos Option, no encapsulado, que será un puntero a una estructura en la que se almacenarán los atributos del objeto. Las funciones exportadas para manejar este tipo de datos serán únicamente la función de creación y la de destrucción. El método execute de la clase Option no puede ser implementado directamente. El subsistema Interface (ver sección ) se encargará de recolectar las acciones a ejecutar y de enviárselas a Main para que las ejecute. La estructura de datos implementada tiene sólo dos campos : char text[]: Texto a mostrar para identificar la opción. Array actions: Grupo de acciones a ejecutar en caso de que el usuario seleccione esta opción. Y las funciones exportadas también son solamente dos:

117 La clase Key 99 Option newoption(void): Devuelve una variable de tipo Option con memoria reservada. void freeoption(option option): Libera la memoria ocupada por la variable option. Al igual que lo comentado para Menu, si las acciones fueron compartidas por otro módulo, estas no serán liberadas hasta que sean liberadas por este otro módulo La clase Key La clase Key se utilizará para almacenar la información sobre las acciones a realizar para cada evento de entrada detectado 3. Como se puede ver en la pulsación de una tecla puede estar asociada a tres tipos de evento: ACTIONS, lo que provocará la ejecución de un grupo de objetos de la clase Action; EXECU- TE, que provocará la ejecución del grupo de objetos Action asociados a la opción seleccionada; o NULL, que indica que la pulsación de la tecla debe ser ignorada. Para implementar este tipo de objetos se define un tipo de datos que apunta a una estructura con dos elementos: KeyBind keybind: Indica el tipo de acción a realizar. El tipo KeyBind es una enumeración que puede tomar los valores KBIND NULL, KBIND EXE- CUTE, o KBIND ACTIONS que se corresponden con los valores NULL, EXECUTE y ACTIONS que puede tomar el atributo event de la clase Key. Array actions: Representa la agregación de acciones a ejecutar. Como ya se comentó para la clase Option el método execute no se implementa directamente. Interface se encargará de pasarle el grupo de acciones correspondiente a Main para que las ejecute en caso de que la tecla pulsada lo requiera: Si la tecla está asociada con un evento EXECUTE se provocará la ejecución de Option.execute, lo que equivale a pasarle a Main el array actions del elemento de tipo Option situado en la posición indicada por el campo currentposition del menú actual en el array options de dicho menú. Si la tecla está asociada con un evento ACTIONS se le pasará a Main el array actions. Si la tecla está asociada a un evento de tipo NULL la llamada a execute no tiene ningún efecto. 3 Un evento de entrada se produce cuando el usuario pulsa una tecla del mando a distancia

118 100 Capítulo 5. Implementación de DFBCIn El atributo key de la clase Key no necesita codificarse explícitamente, ya que los objetos que definen todas las teclas posibles están almacenados en el atributo keys del tipo Menu, la posición en la que está almacenada ya indica qué tecla es. En el fichero input-keys.h se define la enumeración InputKey que se utilizará para indexar los estos objetos. Por ejemplo: Si el usuario pulsa la tecla SEL, el objeto que represente dicha tecla se obtendrá accediendo a (menu->keys)[inpt SEL], suponiendo que menu sea la variable que representa el menú actual La interfaz Action Introducción Los objetos pertenecientes a la case Action van a ser compartidos por diferentes módulos del sistema. Todas las acciones a ejecutar estarán en un principio en alguno de los arrays de algún menú que se haya descargado de VXMLS. Después de esto, se pueden mantener diferentes referencias al mismo array de acciones, por ejemplo, cuando una tecla pasa a estar vinculada con un array de acciones tras la ejecución de una acción BindKey el objeto Key que representa a la tecla vinculada pasa a referenciar el array de acciones que se encuentra entre los datos del objeto BindKey. En caso de que se detecte que el usuario ha pulsado esa tecla, el mismo array de acciones también será referenciado por Main para proceder a su ejecución. Sin embargo, no es necesario controlar las referencias a las acciones en sí, ya que siempre se compartirán a través de un array, y el tipo Array ya implementa el control de concurrencia (ver sección 5.5.2), asegurando que ni él ni su contenido serán liberados hasta que todas las referencias hayan sido liberadas Tipos de datos Implementación de la interfaz Action Para implementar esta interfaz de forma que sea fácil la creación de nuevas acciones que la respeten se ha definido un tipo Action que apunta a una estructura con dos campos: ActionType actiontype: El tipo ActionType se utiliza para definir el tipo de acción que se está representando (es decir, a qué clase pertenece).

119 La interfaz Action 101 ActionData actiondata: El tipo ActionData representa un campo de datos genéricos desde el que se puede acceder a los diferentes atributos de cada tipo de acción implementado. El tipo ActionType será una enumeración en la que se podrán ir añadiendo los nombres de los nuevos tipos de acción que se vayan definiendo. Los tipos de acción que se han implementado para el sistema actual son: NEXT MENU ACTION: Acción para navegar a un nuevo menú PREVIOUS MENU ACTION: Permite volver a un menú anterior, descartando los menús que se hayan visitado después de ese. HIDE MENU ACTION: Oculta el menú actual. SHOW MENU ACTION: Muestra el menú actual. PLAY VIDEO ACTION: Inicia la reproducción de un vídeo. STOP VIDEO ACTION: Detiene el de vídeo que se está reproduciendo. RESUME VIDEO ACTION: Continúa con la reproducción de vídeo anteriormente detenida. SEEK VIDEO ACTION: Salta a una determinada posición del vídeo que se está reproduciendo. UNLOAD VIDEO ACTION: Termina la reproducción de vídeo. CHANGE OPTION ACTION: Cambia la opción actual. BIND KEY ACTION: Cambia el evento asociado a una determinada tecla. SET PROPERTY ACTION: Cambia el valor de una propiedad de personalización. RELOAD MENU ACTION: Vuelve a solicitar el menú actual a VXMLS. SHOW TEXT ACTION: Muestra un texto por pantalla. HIDE TEXT ACTION: Oculta el texto que se estaba mostrando. LOAD MP3 ACTION: Carga un fichero de audio mp3 e inicia su reproducción. PAUSE CONTINUE MP3 ACTION: Detiene/continúa la reproducción de audio en curso.

120 102 Capítulo 5. Implementación de DFBCIn KILL MP3 PLAYER ACTION: Fuerza la eliminación del reproductor de mp3. Esto es necesario porque se necesita liberar el dispositivo /dev/dsp para que la reproducción de vídeo pueda utilizar la tarjeta de sonido. Si se detiene la reproducción de audio con la acción PauseContinueMP3 el dispositivo /dev/dsp sigue estando bloqueado por el reproductor de mp3. El tipo ActionData será un puntero a una unión en la que se podrán definir campos para almacenar los datos necesarios para la ejecución de los diferentes tipos de acción Tipos de datos para las acciones concretas Para las acciones que se han implementado, hay nueve que necesitan información específica que será almacenada en el campo actiondata. Sabiendo qué acción se está tratando (está indicado por el campo actiontype) se puede acceder a sus datos a través de la unión apuntada por ActionData. Estos campos pueden ser uno de los siguientes: NextMenuActionData nextmenuactiondata: El tipo NextMenuActionData se utiliza para almacenar la información que se necesita para ejecutar una acción NextMenu. Apunta a una estructura con los campos: char nextmenuname[]: Nombre del menú a solicitar a VXMLS. Array arguments: Array con los argumentos con los que se va a solicitar el menú, ordenados de forma nombre 1, valor 1, nombre 2, valor 2, etc. PreviousMenuActionData previousmenuactiondata: Las variables de tipo PreviousMenuActionData contienen la información necesaria para ejecutar una acción PreviousMenu. Apunta a una estructura con dos campos: int returndepth: Número de menús a retroceder. short reinit: Si es 0 no se ejecutarán las acciones de inicialización del menú. PlayVideoActionData playvideoactiondata: En este campo se almacena la información que se necesita para ejecutar una acción PlayVideo. El tipo PlayVideoActionData apunta a una estructura con dos campos: char videopath[]: Ruta completa del fichero de vídeo.

121 La interfaz Action 103 Array endactions: Acciones a ejecutar cuando se alcance el final del vídeo. ChangeOptionActionData changeoptionactiondata: El tipo ChangeOptionActionData se utiliza para almacenar la información necesaria para la ejecución de las acciones de tipo ChangeOption. Apunta a una estructura con los campos: int value: Número a sumar a la posición actual, o número de la opción a seleccionar, dependiendo de si absolute sea 0 o distinto de 0. short absolute: Indica si value se debe interpretar como valor a sumar a la posición actual o como posición de destino. BindKeyActionData bindkeyactiondata: En el tipo BindKeyActionData se almacena la información necesaria para la ejecución de las acciones Bind- Key. Apunta a una estructura con los campos: InputKey inputkey: Identificador de la tecla que lanzará el evento definido por key. Key key: Ver la sección 5.8. SeekVideoActionData seekvideoactiondata: En este campo se almacenará la información necesaria para ejecutar las acciones SeekVideo. Como en los casos anteriores, SeekVideoActionData es un tipo que apunta a una estructura con dos campos: SeekVideoType seekvideotype: SeekVideoType es una enumeración que puede tomar los valores: SEEK FORWARD: Se debe incrementar la posición actual en la reproducción del vídeo. SEEK BACKWARD: Se debe decrementar la posición actual. SEEK ABSOLUTE: Se debe ir a la posición indicada. double time: Posición a la que se debe ir o cantidad a aumentar o decrementar la posición actual. SetPropertyActionData setpropertyactiondata: Aquí se almacena la información necesaria para ejecutar las acciones SetProperty. El tipo Set- PropertyActionData apunta a una estructura con dos campos:

122 104 Capítulo 5. Implementación de DFBCIn char name[]: Nombre de la propiedad. char value[]: Nuevo valor para la propiedad. ShowTextActionData showtextactiondata: En este campo se almacenará la información necesaria para ejecutar una acción ShowText. El tipo ShowTextActionData apunta a una estructura con un único campo lines que contiene un array de strings. LoadMp3ActionData loadmp3actiondata: En este campo se almacena la información que se utilizará para ejecutar las acciones de tipo LoadMp3. El tipo LoadMp3ActionData apunta a una estructura que contiene el campo path en el que se indica la ruta desde la que se debe cargar el fichero mp3 a reproducir Funciones El método execute se implementará utilizando una sentencia switch que llamará la función correspondiente de utilizando el campo actiontype de la acción ejecutada. void executeaction(action action, GlobalContext globalcontext) { switch (action -> actiontype) { case NEXT_MENU_ACTION: executenextmenuaction(action -> actiondata -> nextmenuactiondata, globalcontext); break; case PREVIOUS_MENU_ACTION: /* [...] continúa con casos similares */ El argumento globalcontext lo pasa Main cuando llama a execute. Contiene información global sobre la ejecución de la aplicación. Además de las funciones necesarias para simular el método execute también son necesarias las funciones que posibiliten la creación y destrucción de este tipo de objetos. El API para el manejo de objetos de la clase Action proporciona, además de execute, las siguientes funciones:

123 La interfaz Action 105 void freeaction(action action): Libera la memoria ocupada por la variable action. void freeaction(void *data): Alias de la función anterior para utilizar en la creación de los arrays de acciones (ver sección 5.5.2). Action newaction(void): Devuelve una nueva acción con actiontype como NO ACTION y actiondata igual a NULL. Estos campos deberán ser rellenados explícitamente con los datos correspondientes a la acción que se quiera representar. Al igual que la función execute, la función freeaction deberá implementar una sentencia switch para liberar la memoria ocupada por los datos específicos de la acción. void freeaction(action action) { if (action -> actiondata!= NULL) { freeactiondata(action -> actiondata, action -> actiontype); } } free(action); static void freeactiondata(actiondata actiondata, ActionType actiontype) { switch (actiontype) { case NO_ACTION: // Falls through case SHOW_MENU_ACTION: // Falls through case STOP_VIDEO_ACTION: // Falls through /* * [...] * * Continúa con todas las acciones que no * necesitan datos adicionales */

124 106 Capítulo 5. Implementación de DFBCIn break; case NEXT_MENU_ACTION: freenextmenuactiondata(actiondata); break; case PREVIOUS_MENU_ACTION: freepreviousmenuactiondata(actiondata); break; /* * [...] * * Continúa con el resto de funciones de * liberación de actiondata s */ default: DFBCIN_FATAL(IMPLEMENTATION_ERROR); break; } } Para aquellas acciones que no necesiten datos específicos no será necesario realizar ninguna acción adicional a la hora de liberar la memoria ocupada ya que el campo actiontype será un puntero NULL. Para el resto de acciones se deberá añadir el código que se encargue de liberar los tipos de datos que utilizan para almacenar la información extra. Las funciones de creación y liberación para los tipos de datos definidos para almacenar la información necesaria para ejecutar las acciones también serán exportados por el API, ya que serán necesarios para completar las variables devueltas por newaction. newnextmenuactiondata(const char *menuname) newpreviousmenuactiondata(int depth, short reinit) newplayvideoactiondata(const char *videopath)

125 La interfaz Action 107 newchangeoptionactiondata(int value, short absolute) newbindkeyactiondata(inputkey inputkey, Key key) newseekvideoactiondata(seekvideotype type, double time) newsetpropertyactiondata(char *name, char *value) newshowtextactiondata(void) newloadmp3actiondata(const char *path) void freenextmenuactiondata(actiondata actiondata) El resto de funciones de liberación son idénticas a la anterior con el nombre de la acción correspondiente Cómo instanciar una acción? Por ejemplo, si se necesita una acción que al ejecutarla se encargue de solicitar el menú de nombre mainmenu con el atributo test con valor yes a VXMLS sería necesario el siguiente código 4 : Action action; NextMenuActionData nextmenuactiondata; action = newaction(); nextmenuactiondata = newnextmenuactiondata("mainmenu"); addarray(nextmenuactiondata -> arguments, test); addarray(nextmenuactiondata -> arguments, yes); action -> actiontype = NEXT_MENU_ACTION; action -> actiondata -> nextmenuactiondata = nextmenuactiondata; La llamada al método action.execute se implementa utilizando la función execute(action). Para liberar la memoria ocupada tanto por action como por nextmenuactiondata sólo sería necesaria una llamada freeaction(action). 4 test y yes deberán ser strings con memoria reservada e inicializados como test y yes respectivamente

126 108 Capítulo 5. Implementación de DFBCIn Cómo añadir una nueva acción? Los pasos que se deberán seguir para añadir un nuevo tipo de acción (lo que en diseño equivaldría a una nueva implementación de la interfaz Action) son: 1. En caso de que sea necesario, crear un nuevo tipo de datos para almacenar información para ejecutar la acción y las funciones para crear y liberar variables de ese tipo de datos. Estas funciones deberán ser exportadas para el resto de la aplicación. 2. Añadir un campo del tipo anteriormente definido a la enumeración Action- Data. 3. Añadir un identificador para la nueva acción a la enumeración ActionType. 4. Suponiendo NuevaAccion como nombre del nuevo tipo de acción que se está creando: implementar las funciones executenuevaaccion con el código para ejecutar la acción. 5. Añadir los nuevos casos a los switch de executeaction y freeaction Implementación del motor de la aplicación Main La implementación de la clase Main consistirá simplemente en la función main, que será la que se ejecute al iniciar la aplicación. Los pasos que debe seguir esta función serán: 1. Crear una variable de tipo GlobalContext que será pasada a la función execute a la hora de ejecutar las acciones para permitir que modifiquen el estado de la ejecución. En la implementación actual el tipo GlobalContext solamente contiene una pila en la que se irán almacenando los menús a medida que el usuario profundiza en la interfaz definida y una bandera para controlar los cambios en el sistema de propiedades para saber si debe ser salvado a disco. 2. Inicializar los subsistemas necesarios (lo que en diseño equivale a crear los objetos Singleton [38]). Para ello deberá ejecutar las funciones ***Init correspondientes: propertiesinit()

127 Implementación del motor de la aplicación 109 vxmlsinit() graphicsinit(argc, argv) interfaceinit() interfaceinputinit() 3. Obtener el menú principal de VXMLS, añadirlo a la pila de menús e indicarle al módulo gráfico que lo muestre por pantalla. Para ello deberá utilizar el módulo VXMLS y el API del módulo gráfico. /* Load main menu */ menu = vxmlsgetmenu(root_menu, NULL); pushstack(globalcontext -> menustack, menu); /* Show main menu */ interfaceloadmenu(menu, 1); interfaceshowmenu(); 4. Esperar a recibir bloques de acciones a ejecutar y ejecutarlos cuando estén disponibles. Normalmente, el primer bloque de acciones a ejecutar serán las acciones especificadas en el atributo initactions del menú principal. Después de la ejecución de cada bloque de acciones se comprueba si se ha modificado el sistema de propiedades y en caso de que sea así, se salva su contenido en el disco 5. while (1) { array = interfacewaitforactions(); for (i = 0; i < numarrayelements(array); i++) { action = (Action) getarraydata(array, i); executeaction(action, globalcontext); } /* Save the properties to disk if needed */ if (globalcontext -> saveproperties) { propertiessave(); globalcontext -> saveproperties = 0; 5 El sistema de propiedades se dejó de utilizar para almacenar datos cambiantes en cuanto el control de este tipo de datos pasó a VXMLS, por lo que este paso es innecesario en la implementación actual

128 110 Capítulo 5. Implementación de DFBCIn } } /* Release executed actions */ releasearray(array); Interface Introducción La implementación del objeto de la clase Interface se hará siguiendo los pasos explicados en la sección 5.4. La función interfaceinit creará un nuevo hilo de ejecución que se encargará de ejecutar la función interfacethread que controlará la comunicación con el módulo gráfico y con InterfaceInput y detectará los arrays de acciones que deben ser ejecutados Banderas de estado Para definir el estado con el que controlar la ejecución del nuevo hilo de ejecución se utiliza un sistema de banderas. Las banderas definidas son: INTST MENU LOAD: Si está activa quiere decir que hay un menú cargado. INTST SHOW MENU: Las funciones exportadas activarán esta bandera para indicarle a interfacethread que debe mostrar el menú cargado. INTST HIDE MENU: Esta bandera se activará para indicar que se debe ocultar el menú. INTST INPUT EVENT: Esta bandera será activada para señalar que hay un nuevo evento de entrada que atender. INTST ACTION READY: Si está activa indica que hay acciones listas para ser ejecutadas. INTST WAITING ACTION: Se activa para indicar que Main está esperando para recibir acciones a ejecutar. INTST NEW FRAME: La activará el sistema de reproducción de vídeo para indicar que se ha decodificado un nuevo frame y que debe ser mostrado en la pantalla.

129 Implementación del motor de la aplicación 111 INTST VIDEO LOAD: Se activará para indicar que se debe cargar un nuevo vídeo. INTST VIDEO UNLOAD: Se deberá activar para indicar que se debe terminar la reproducción de vídeo. INTST VIDEO PLAY: Con esta bandera se señala que se debe comenzar la reproducción del vídeo cargado. INTST VIDEO STOP: Se utiliza para indicar que se debe detener la reproducción en curso. INTST VIDEO RESUME: Se activará cuando se desee continuar con la reproducción de vídeo anteriormente detenida. INTST VIDEO PLAYBACK: Si está activa indica que se está reproduciendo un vídeo (se mantiene activa aunque la reproducción esté temporalmente detenida). INTST MENU INIT: Se activará si se deben ejecutar las acciones de inicialización de un menú. INTST VIDEO END: Indica que se ha alcanzado el final del vídeo. INTST EXIT: Se utiliza para terminar la aplicación, solamente es necesaria para las pruebas del sistema. INTST SHOW TEXT: Se activará para señalar que se debe mostrar un texto en la pantalla. INTST HIDE TEXT: Se activará para que interfacethread oculte el texto anteriormente mostrado. Estas banderas no son accesibles para el resto de la aplicación, sólo serán manipuladas por las funciones exportadas para el resto de módulos y por las funciones internas de Interface Funciones exportadas La mayoría de las funciones exportadas al resto de la aplicación se limitarán a activar o desactivar algunas de las banderas del estado (siempre después de cerrar el semáforo) y despertar el hilo interfacethread para que ejecute las operaciones pertinentes. Las funciones exportadas son:

130 112 Capítulo 5. Implementación de DFBCIn void interfaceinit(void): Simula la creación del objeto Singleton [38], para ello reserva la memoria necesaria para almacenar el estado (definido por la variable interfacestate) y crea el nuevo hilo interfacethread. void interfacedeinit(void): Destruye el objeto creado por la función anterior, para ello finaliza el hilo interfacethread y libera la memoria ocupada por la variable de estado. void interfaceloadmenu(menu menu, short init): Se utiliza para cargar un nuevo menú en la interfaz. init indica si se deben ejecutar las acciones de inicialización. Esta función activa la bandera INTST MENU LOAD y, en caso de que init sea distinto de 0, también activa INTST MENU INIT. void interfaceunloadmenu(void): Solicita la descarga del menú anteriormente cargado activando INTST MENU UNLOAD. void interfaceshowmenu(void): Activa INTST SHOW MENU. void interfacehidemenu(void): Activa INTST HIDE MENU. void interfacenotifyinputevent(void): Esta función será utilizada por InterfaceInput para indicar que se ha detectado un nuevo evento de entrada que debe ser tratado. Activa la bandera INTST INPUT EVENT. void interfaceloadvideo(char *videofile, Array endactions): Activa INTST VIDEO LOAD, copia videofile en un campo de la variable de estado y añade una referencia a endactions, para tener disponibles las acciones del final del vídeo en caso de que este se produzca. void interfaceplayvideo(void): Activa INTST VIDEO PLAY. void interfacestopvideo(void): Activa INTST VIDEO STOP. void interfaceresumevideo(void): Activa INTST VIDEO RESUME. void interfaceunloadvideo(void): Activa INTST VIDEO UNLOAD. void interfaceshowtext(array lines): Activa INTST SHOW TEXT y carga las líneas de texto en el módulo gráfico. void interfacehidetext(void): Activa INTST HIDE TEXT. Array interfacewaitforactions(void): En caso de que no esté activa la bandera INTST ACTION READY, activa INTST WAITING ACTION y bloquea la ejecución en la condición actioncond durante el tiempo indicado por el

131 Implementación del motor de la aplicación 113 campo time del menú cargado (durante tiempo infinito si este valor es -1). En caso de que finalice la temporización referencia el array timeactions del menú cargado en el array que se mantiene en el estado con las funciones listas para ser ejecutadas y activa INTST ACTION READY. Finalmente comprueba si ya está activa al bandera INTST ACTION READY y en caso contrario vuelve al bloqueo en la condición actioncond Ciclo de ejecución El ciclo de ejecución del hilo interfacethread se mantiene dormido hasta que alguna de las funciones anteriores lo despierta. Tras esto comprueba las variables de estado y ejecuta las funciones que sean necesarias. En primer lugar, en caso de que no esté activa INTST ACTION READY comprueba si hay acciones listas para ejecutarse: 1. Si está activa la bandera INTST MENU INIT la desactiva y guarda el array initactions del menú cargado para devolverlo cuando se soliciten las acciones a ejecutar. 2. Si está activa la bandera INTST VIDEO END la desactiva y guarda el array de acciones endvideoactions para devolverlo como acciones a ejecutar. 3. Si está activa la bandera INTST INPUT EVENT recuperará la tecla pulsada utilizando la función getinputkey de InterfaceInput y comprobará el objeto Key correspondiente a dicha tecla en el menú cargado. Si la pulsación de esa tecla está asociada a la ejecución de un grupo de acciones guardará esas acciones para devolverlas como acciones a ejecutar, en caso de que la tecla esté vinculada a un evento EXECUTE, guardará el array de acciones de la opción señalada por el parámetro currentposition del menú cargado. En caso de que la tecla esté asociada a un evento NULL, la entrada será ignorada (ni siquiera detiene la temporización). Si en el paso anterior se ha detectado un array de acciones a ejecutar se activa la bandera INTST ACTION READY. En caso de que esté activa la bandera INTST WAITING ACTION se despierta a los hilos que estén esperando en la condición ActionCond (en la función interfacewaitforactions). Si está activa la bandera INTST VIDEO PLAY, se desactiva y se comienza la reproducción de vídeo utilizando la biblioteca gráfica. También se activa la bandera INTST VIDEO PLAYBACK y se indica a la biblioteca gráfica que

132 114 Capítulo 5. Implementación de DFBCIn a partir de ese momento dibuje los menús dentro de un marco, ya que se superpondrán a la imagen de vídeo. Si está activa la bandera INTST NEW FRAME se desactiva y se indica que debe ser redibujada la pantalla activando una variable local flip. Para controlar la reproducción del vídeo se comprueba si esta activa alguna de las banderas INTST VIDEO STOP o INTST VIDEO RESUME en caso de que así sea, se desactiva y se utiliza la biblioteca gráfica para detener o continuar la reproducción en curso. Si está activa la bandera INTST VIDEO LOAD se desactiva y se carga el fichero de vídeo indicado en la variable de estado en el módulo gráfico. Si está activa la bandera INTST VIDEO UNLOAD se desactiva, se descarga el vídeo del módulo gráfico y se indica al mismo que deje de dibujar el marco de los menús. También se libera el array endvideoactions anteriormente referenciado durante la ejecución de la función interfaceloadvideo. Las banderas INTST SHOW MENU y INTST HIDE MENU provocarán que se cargue o descargue el menú en el módulo gráfico respectivamente en caso de que estén activadas. Ambas serán desactivadas una vez realizada la operación correspondiente. Para hacer que los cambios realizados sean visibles se debe redibujar la pantalla, por lo que también se activa la variable flip. Las banderas INTST SHOW TEXT y INTST HIDE TEXT provocarán un comportamiento similar a las dos anteriores, pero con líneas de texto en lugar del menú. Por último, en caso de que esté activa la variable flip, utilizará las funciones del API del módulo gráfico para dibujar en pantalla lo que sea necesario. Si está activa la bandera INTST VIDEO PLAYBACK llamará a la función graphicsblitvideo para dibujar el frame actual como fondo, después llamará a la función graphicsflipscreen que dibujará el resto de la interfaz gráfica (menú y/o texto) y hará los cambios visibles. Tras esto desactiva la variable flip InterfaceInput Al igual que Interface la implementación de InterfaceInput también se hará de acuerdo con lo explicado en la sección 5.4.

133 Implementación del motor de la aplicación 115 La función intefaceinputinit reservará memoria para almacenar el estado y creará un nuevo hilo de ejecución interfacethread que monitorizará la entrada y avisará a Interface cada vez que detecte que el usuario ha pulsado una tecla. El estado de este subsistema se compone de unas banderas y un espacio para almacenar un evento detectado. Las banderas de estado son: INPTST EVENT DETECTED: Se activará cuando se detecte un evento de entrada. INPTST EVENT STORED: Se mantendrá activa mientras se tenga almacenado un evento anteriormente detectado a la espera de que sea consultado por Interface. El ciclo de ejecución del hilo que controla este objeto sigue los siguientes pasos: 1. Si no está activa la bandera INPTST EVENT STORED hace una llamada a la función graphicstestinput del modulo gráfico. Esta función bloqueará la ejecución hasta que se detecte un evento de entrada. Una vez obtenido el evento de entrada, comprueba si éste es válido y, en caso de que así sea, activa INPTST EVENT DETECTED y INPTST EVENT STORED. 2. Si está activa la bandera INPTST EVENT STORED la desactiva y llama a la función interfacenotifyinputevent. 3. Mientras esté activa la bandera INPTST EVENT STORED detiene su ejecución. Este módulo exporta la función getinputkey que devuelve el evento almacenado y desactiva la bandera INPTST EVENT STORED. Esta función debe bloquear el semáforo antes de acceder al estado, por lo que sólo podrá completar su ejecución en caso de que el hilo interfaceinputthread esté dormido. Tras devolver el evento detectado despierta el hilo para que continúe su ejecución. Para destruir el objeto creado, se exporta la función interfaceinputdeinit, que detiene la ejecución del hilo creado por la función de inicialización y libera la memoria ocupada por la variable de estado.

134 116 Capítulo 5. Implementación de DFBCIn Mp3Player Introducción Esta clase también es una aplicación del patrón Singleton [38], por lo que se implementará de acuerdo con lo explicado en 5.4. Para la reproducción de los ficheros o URLs se utilizará el programa mpg123. Este programa define un protocolo de comunicación utilizando la entrada y salida estándar, lo que permite controlarlo desde DFBCIn utilizando un pipe y redirección de ficheros Banderas de estado Las banderas utilizadas para el control del hilo de ejecución de este objeto son: PLST LOAD: Se activa para indicar que se debe iniciar la reproducción de un cierto fichero o URL. PLST PAUSE CONTINUE: Se activa para indicar que se debe detener la reproducción en curso o continuar con una reproducción anteriormente detenida. PLST QUIT: Se activa para indicar que se debe terminar la ejecución del programa mpg123. PLST PAUSED: Se activará cuando la reproducción esté detenida Funciones exportadas La función mp3init se encargará de crear el objeto. Para ello ejecuta las siguientes operaciones: 1. Crea dos pipes, uno para enviar comandos a mpg123 y otro para leer información del mismo. 2. Crear un nuevo proceso del sistema operativo con una llamada fork. La entrada estándar de este nuevo proceso se redirige al extremo de lectura del pipe de comandos y la salida estándar se redirige al extremo de escritura del pipe de información. Tras esto se ejecuta el programa mpg123 con una llamada exec.

135 Implementación del módulo VXMLS Crear un nuevo hilo de ejecución que monitorice la ejecución de mpg123 utilizando los pipes anteriormente creados. Antes de crear este nuevo hilo, se asegura que mpg123 está funcionando correctamente leyendo el mensaje de confirmación del pipe de información. La función mp3load llamará a mp3init en caso de que el objeto no haya sido creado (es decir, que no exista el hilo de control), tras esto bloquea el estado, activa la bandera PLST LOAD y, en caso de que esté activa la bandera PLST PAUSED, despierta el hilo de control. La función mp3pausecontinue obtiene el bloqueo del estado, activa la bandera PLST PAUSE CONTINUE y, en caso de que esté activa la bandera PLST PAUSED, despierta el hilo de control. La función mp3deinit bloquea el estado, activa la bandera PLST QUIT, despierta el hilo de control en caso de que esté activa la bandera PLST PAUSED, libera el estado, espera a que finalice el hilo y después espera a que termine la ejecución de mpg Ciclo de ejecución El hilo de control sigue los siguientes pasos en su ciclo de ejecución: 1. Si está activa la bandera PLST PAUSED bloquea su ejecución en una condición, a la espera de ser despertado por alguna de las funciones exportadas. 2. Si no está activa la bandera PLST PAUSED, lee una línea del pipe de información para asegurarse de que la reproducción no ha llegado a su fin, en cuyo caso volverá a empezarla desde el principio. Tras esto libera el estado, cede la CPU para permitir la ejecución de las funciones exportadas y vuelve a bloquear el estado. 3. Si está activa la bandera PLST LOAD, la desactiva y escribe el comando para cargar la URL en el pipe de comandos y lee la confirmación del pipe de información. 4. Si está activa la bandera PLST PAUSE CONTINUE la desactiva y escribe el comando para detener o reanudar la reproducción. Tras esto lee la información devuelta y activa o desactiva la bandera PLST PAUSED según sea necesario. 5. Si está activa la bandera PLST QUIT escribe el comando para terminar la ejecución de mpg123 y termina termina el hilo, en caso contrario vuelve al paso 1.

136 118 Capítulo 5. Implementación de DFBCIn Implementación del módulo VXMLS Módulo HTTP Introducción La comunicación con VXMLS se hará mediante peticiones GET [35]. Para poder realizar estas peticiones se utilizará la clase utilidad HTTP que proporciona las funciones httpget y escapedencoding que permiten enviar peticiones GET genéricas al puerto de un servidor. Lógicamente, no se ha realizado una implementación completa de un cliente HTTP, sino que sólo se pretende que sea posible realizar peticiones a VXMLS. Aún así, el servidor y el puerto se pasan como parámetros para respetar la modularidad del sistema. En [42] se definen la sintaxis que deben respetar las URLs (una URL es un tipo especial de URI). La función escapedencoding transformará cadenas de texto utilizando la codificación hex hex, para evitar que los caracteres reservados que se puedan encontrar en esas cadenas varíen la semántica de la URL. Por ejemplo, si se quiere pasar un argumento un-&-es-un-caracter-reservado deberá ser previamente codificado para evitar que el caracter & sea interpretado como separador de argumentos: strcpy(argumento, "un-&-es-caracter-reservado"); escapedencoding(argumento); puts(argumento); > un-%26-es-caracter-reservado Peticiones GET La función httpget se encargará de hacer una petición GET HTTP sobre una URL de un cierto servidor que esté escuchando en un puerto determinado. Para ello se implementarán las partes necesarias del protocolo HTTP. Para mantener las sesiones de los diferentes usuarios se utilizará un sistema de cookies [45]. Este sistema se implementará de forma sencilla; sólo se necesita poder almacenar una única cookie en memoria, se supone que la sesión sólo será mantenida mientras que el cliente esté funcionando. Envío de peticiones GET HTTP 1.1, contemplando la posibilidad de enviar el campo Cookie en caso de que sea necesario. Interpretación de ciertos campos de la cabecera de la respuesta del servidor:

137 Implementación del módulo VXMLS 119 Connection: En caso de que contenga el valor close, se puede asumir que el servidor cerrará la conexión en cuanto termine de enviar el mensaje. Content-Length: Este campo se utilizará para indicar cuántos bytes se deben leer para obtener la respuesta completa. El servidor HTTP implementado por Inets [39] devuelve el campo Connection con valor close en lugar de devolver la longitud de la respuesta. Set-Cookie: Este campo indica que se debe almacenar una determinada cookie. La cookie almacenada se enviará en todas las siguientes peticiones en el campo Cookie de la cabecera GET. Set-Cookie también puede ser utilizado para ordenar al cliente la destrucción de una cookie previamente almacenada. VXMLS-Error: Este campo se ha definido para que VXMLS pueda advertir a DFBCIn de que el contenido que le envía puede no ser el esperado, ya que se ha producido un error Envío de peticiones GET Para enviar peticiones GET se utiliza la función int httpget(char *server, int port, char *request, int filedes) que ejecuta los siguientes pasos para enviar la petición request al puerto port del servidor server HTTP y escribir la respuesta en el descriptor de fichero filedes. 1. Abre un socket y envía la petición. De esto se encarga una función interna sendrequest mediante los pasos: a) Crear un socket orientado a conexión. b) Obtener la dirección de server. c) Conectar con el servidor utilizando el socket. d) Crear la cabecera GET a enviar con la URL request y el campo Cookie en caso de que sea necesario. e) Enviar la petición 2. Leer la cabecera de la respuesta para obtener el tamaño del contenido (o asegurarse de que se ha devuelto el campo Connection con valor close) y guardar una nueva cookie o destruir la cookie almacenada en caso de que sea necesario. Si se detecta el campo VXMLS-Error se escribirá un aviso en el error estándar para clarificar las causas del fallo.

138 120 Capítulo 5. Implementación de DFBCIn 3. Leer el resto del mensaje y escribirlo en el filedes hasta que se alcance el final, ya sea el marcado por el campo Content-Length o el marcado por el cierre de la conexión por parte del servidor (en caso de que el anterior campo no hubiera sido devuelto) Parser VXMLS La estructura de los documentos XML devueltos por VXMLS para las operaciones que deben ser confirmadas es muy sencilla (ver el apéndice A), lo que facilita la elaboración del parser para interpretarlos. El API exportado por el parser VXMLS exporta dos funciones al resto módulos: parsevxmlsresponse para interpretar las repuestas de VXMLS y la función getvxmlserrormessage que devuelve un mensaje explicativo en el caso de que se haya producido algún error. Para almacenar el estado interno del parser durante el proceso de parsing se define una estructura con los campos: AppError error: Para indicar qué error se produjo en caso de que se produjera alguno. char errormessage[]: Mensaje devuelto por VXMLS explicando el error. short inerror: Se utiliza para indicar que se está interpretando el contenido de la etiqueta error. short abort: Se activará en caso de que se detecte un error que obligue a abortar el proceso de parsing. En el parser creado se instalarán los siguientes manejadores (ver sección 3.4.3): startelement: Se instala para manejar la apertura de las etiquetas. Si está activo el campo abort no hace nada. Si la etiqueta que se está abriendo es la etiqueta ok pone el valor NO ERROR en el campo error del estado del parser para indicar que VXMLS confirmó la operación. Si la etiqueta que se está abriendo es la etiqueta error pone el valor VXMLS ERROR en el campo error del estado del parser para indicar que VXMLS ha fallado al realizar la operación y activa inerror.

139 Implementación del módulo VXMLS 121 En otro caso, si la etiqueta abierta no es vxmls (etiqueta raíz del documento esperado) se pone el valor PARSER ERROR en el campo error para indicar que la respuesta de VXMLS es incomprensible y se activa abort. endelement: Se instala para manejar el cierre de las etiquetas. Si está activo el campo abort no hace nada. Si la etiqueta que se está cerrando es la etiqueta error desactiva el campo inerror del estado del parser y copia el mensaje de error errormessage en una variable global para que pueda ser devuelto por la función getvxmlserrormessage. characterdata: Se instala para manejar las secciones de caracteres. Su objetivo es copiar la sección de datos de la etiqueta error en el campo errormessage del estado del parser. Lo único que deberá hacer esta función será concatenar los datos que recibe como argumentos en el campo errormessage en caso de que el campo inerror esté activo. La función AppError ParseVxmlsResponse(int filedes) creará un nuevo parser utilizando el API de expat, le instalará los manejadores anteriormente definidos y lo utilizará para parsear los contenidos del fichero descrito por filedes. Devuelve un código de error, en caso de que todo haya ido bien, el código devuelto es NO ERROR Parser para los documentos menu Introducción La estructura de un documento XML utilizado para describir un determinado menú de la interfaz pude ser arbitrariamente profunda (ver el apéndice A) debido a que algunos tipos de acción pueden contener descripciones de otras acciones en su interior. Además de esto, el numero de acciones descritas es susceptible de ser aumentado con frecuencia, por lo que se deberá implementar el parser de forma que el hecho de añadir nuevas acciones no afecte al código existente. Para resolver el problema de la profundidad arbitraria se utilizará una pila en el estado del parser. Las funciones utilizadas por éste podrán utilizar la pila para almacenar la información necesaria entre la apertura y el cierre de las etiquetas. En esta pila se almacenará un tipo de datos llamado Context que apunta a una

140 122 Capítulo 5. Implementación de DFBCIn estructura con dos campos, un campo tag en el que se indicará a qué etiqueta pertenece el contexto y un campo data en el que se almacenará la información específica (será de tipo puntero a void, las funciones específicas de cada etiqueta deberán hacer la transformación de tipo necesaria). El caso de la extensibilidad se resuelve estructurando el código de forma que las funciones que controlan la interpretación de la parte estable del documento y las funciones que controlan la parte cambiante estén lo más desacopladas posible Organización del código El código se distribuye de la siguiente forma, para permitir añadir las funciones necesarias para parsear nuevas acciones de forma sencilla: éstas La cabecera parser.h en la que se define la única función que va a ser exportada para el resto de la aplicación: parsemenu. La cabecera parser-types.h en la que se definen los tipos que van a ser utilizados tanto en la parte estable como en la parte que define las acciones. Estos tipos son: Tag: Enumeración utilizada para definir cada una de las posibles etiquetas que se pueden encontrar de acuerdo con el DTD, por ejemplo, la etiqueta <option...> se corresponderá con una variable de tipo Tag con valor OPTION. Context: Contiene la información relativa a una etiqueta abierta, como se explicó al principio de esta sección. ParserData: Es el tipo que tendrá la variable que representa el estado del parser durante el proceso de interpretación. Apunta a una estructura con dos campos, en uno estará la pila de contextos y en otro el objeto de la clase Menu que se irá construyendo a medida que se interpreta la información del documento. BindKeyContextData: Este tipo es necesario para almacenar la información que se necesitará durante el proceso de interpretación del contenido de la etiqueta bindkey. Para el manejo del tipo Context se declaran tres funciones: 6 Como parte cambiante se entiende lo que va dentro de las etiquetas action, sin incluir

141 Implementación del módulo VXMLS 123 Context newcontext(tag tag, void *data): Crea una variable de tipo Context para la etiqueta representada por tag y con los datos apuntados por data. void freecontext(context context): Libera el espacio que ocupa el contexto context pero no el que ocupan sus datos. void freecontextanddata(context context): Libera el espacio reservado para context y los datos que referencia. En el fichero parser.c se define la función parsemenu y la parte estable de las funciones que componen el parser, así como las funciones gettag, que transforma un string con el nombre de una etiqueta en una variable de tipo Tag; freecontext y freecontextanddata; y getattrvalue que será utilizada por las funciones que manejan la apertura de las etiquetas para obtener los valores de los argumentos XML de esas etiquetas, por ejemplo, para la apertura <ejemplo nombre="valor"> la llamada getattrvalue(attrs, "nombre"), devolverá "valor" (attrs es un conjunto de pares nombre-valor que proporciona la implementación genérica de parser hecha por expat). Por último, en los ficheros tag-functions.h y tag-functions.c se implementan las funciones que controlarán la apertura y el cierre de las acciones específicas Proceso de parsing Cómo conseguir una independencia lógica aceptable si todas las funciones trabajan sobre la misma pila y el mismo objeto Menu? El propio proceso de parsing facilita la solución de este problema. Como se explicó en la sección , las etiquetas menos profundas no se ven afectadas por las labores de las más profundas ya que estas trabajarán en la pila por encima de sus datos. Por lo tanto, el proceso de parsing de la parte estable de los documentos puede hacerse sin tener en cuenta los pasos que deberán dar las funciones que interpreten las acciones específicas. Un aspecto que debe tenerse en cuenta es que las funciones que trabajan con acciones específicas pueden necesitar utilizar etiquetas action, que son parte de lo que se considera parte estable de los documentos. Aún así el tratamiento de las etiquetas action puede hacerse de forma genérica con un pequeño truco que se explicará un poco más adelante en la sección Dentro de parser.c, las funciones que manejarán los eventos de apertura, cierre y datos de las etiquetas serán:

142 124 Capítulo 5. Implementación de DFBCIn managestartelement: Recibe como argumentos: ParserData parserdata: La variable de estado del parser. const XML Char **attrs: Array de strings con los nombres y los valores de los atributos con los que fue abierta la etiqueta. Se puede utilizar la función getattrvalue como se explicó anteriormente para obtener el valor de un determinado argumento de forma sencilla. Tag tag: Identifica la etiqueta que se está interpretando. manageendelement: Recibe los argumentos: ParserData parserdata: La variable de estado. Tag tag: Identifica la etiqueta que se está cerrando. managecharacterdata: Recibe los argumentos: ParserData parserdata: La variable de estado del parser. const XML Char **text: Fragmento del contenido PCDATA de la etiqueta. int length: Longitud del fragmento de datos text. tag Tag: Etiqueta que se está tratando. Dentro de cada una de estas funciones habrá un bloque switch que ejecutará el código correspondiente en función del valor de tag. Para los valores MENU, VERSION, TIMER, INIT ACTIONS, OPTION, TEXT, HEADER y ACTION, el código estará dentro de este mismo fichero; estas son las etiquetas que no cambiarán. El resto de etiquetas (las que definen los diferentes tipos de acción) provocarán una llamada a alguna de las funciones declaradas en el fichero tag-functions.h. Estas tres funciones no son las que se instalan directamente como manejadores en el parser creado con expat [2], las funciones que espera expat tienen unos argumentos ligeramente diferentes. Los manejadores instalados actuarán como adaptadores entre expat y las tres funciones anteriormente explicadas. startelement: Llama a managestartelement. Recibe los siguientes argumentos del parser creado con expat: void *userdata: Contiene la variable de estado instalada en el momento de crear el parser. Será convertida al tipo ParserData y se pasará en el argumento parserdata de managestartelement.

143 Implementación del módulo VXMLS 125 const XML Char *name: Nombre de la etiqueta. Se obtendrá el valor Tag correspondiente usando la función gettag y se pasará en el argumento tag const XML Char **attributes: Este valor se pasa tal cual. endelement: Llama a manageendelement, su comportamiento es idéntico al de startelement, pero no recibe el argumento attributes. characterdata: Llama a managecharacterdata. Recibe los siguientes argumentos: void *userdata: Se convertirá al tipo ParserData y se pasará en el atributo parserdata. const XML Char *text: Este atributo se pasa tal cual. int length: Al igual que text, se pasa tal cual. Como se puede ver, characterdata no recibe el argumento name, por lo que en principio no se sabe a qué etiqueta pertenecen los datos. Además, expat no garantiza que se haga una única llamada a characterdata para cada bloque de datos, sino que puede que los datos de una misma etiqueta se lean con más de una llamada a esta función. La solución a ambos problemas: cuando para una etiqueta se necesite leer su contenido, en la apertura de la misma se apilará un contexto con espacio reservado en el que se irán concatenando los fragmentos de información leída. managecharacterdata obtendrá el contexto de la cima de la pila y comprobará el valor del atributo tag del mismo. Este valor se le pasará a la función managecharacterdata. Es decir, si para una determinada etiqueta es necesario leer su contenido, es obligatorio que después de que se ejecute managecharacterdata para dicha etiqueta en la cima de la pila se encuentre un contexto con el valor tag correspondiente a la etiqueta que se está tratando Interpretación de la parte estable de los documentos Los pasos que se dan para interpretar las etiquetas que forman la parte estable de los documentos son: Para la etiqueta menu no es necesario hacer nada, ni en la apertura ni en el cierre de la misma. La etiqueta version contiene datos de caracteres en su interior, por lo tanto, en su apertura se apilará un nuevo contexto con espacio para que managecharacterdata copie el contenido de la etiqueta (appmalloc devuelve un puntero a un bloque de memoria reservada):

144 126 Capítulo 5. Implementación de DFBCIn string = (char *) appmalloc(10); string[0] = \0 ; context = newcontext(version, string); pushstack(parserdata -> stack, context); La función managecharacterdata concatenará los datos que vaya leyendo en el espacio de datos del contexto que se encuentre en la cima de la pila: context = (Context) seestacktop (parserdata -> stack); string = (char *) context -> data; strncat(string, text, length); Por último, en el cierre de la etiqueta se desapila el contexto de la cima de la pila, cuya sección de datos contendrá la cadena de caracteres completa leída del interior de la etiqueta, interpreta esta cadena para obtener los números de versión, los copia en el menú incompleto contenido en el estado del parser (estas dos operaciones las realiza parseversion) y comprueba que la versión está soportada. Por último libera la memoria ocupada por context y por los datos que contiene. context = (Context) popstack(parserdata -> stack); if (context -> tag!= VERSION) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } parseversion(context -> data, &(parserdata -> menu -> majorversion), &(parserdata -> menu -> minorversion)); if(unsupportedversion(paserdata -> menu)) { DFBCIN_FATAL(VERSION_ERROR); } freecontextanddata(context); La interpretación de la etiqueta header se implementa de forma similar a la de la etiqueta version, pero en el cierre de la misma la única operación que hay que realizar es desapilar el contexto correspondiente y copiar su contenido en el campo header del menú que se está construyendo:

145 Implementación del módulo VXMLS 127 context = (Context) popstack(parserdata -> stack); if (context -> tag!= HEADER context -> data == NULL) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } strcpy(parserdata -> menu -> header, (char *) context -> data); freecontextanddata(context); Para implementar la interpretación de action hay que tener en cuenta que, aunque action se haya considerado parte de la estructura estable de los documentos, las etiquetas que definan nuevas acciones pueden incluir etiquetas action en su interior. Se puede suponer que las acciones siempre van a ser leídas en grupos, ya que, como se vio en apartados anteriores, las acciones se ejecutan en bloques. Por lo tanto, las acciones siempre van a ser almacenadas dentro de arrays. Aprovechando esta situación, se definirá una etiqueta especial ARRAY TAG, que no representa a ninguna etiqueta que pueda estar presente en los documentos, sino que representará un contexto especial cuyo campo de datos contiene un array en el que se almacenarán las acciones que se vayan interpretando. De esta forma, si una etiqueta necesita recolectar las acciones que hay en su interior, deberá dejar un contexto ARRAY TAG en la cima de la pila tras su apertura y en su cierre podrá desapilarlo y recoger las acciones que se hayan interpretado. La interpretación de una etiqueta action consistirá, por tanto, en: En su apertura, se crea una acción vacía y se pone en un contexto en la cima de la pila a la espera de que las etiquetas anidadas dentro de action la definan. De esta forma, en la implementación de una acción específica lo que se deberá hacer es asegurar que, en el cierre de la etiqueta que define la acción, se deje en la cima de la pila este mismo contexto con la acción ya completa. action = newaction(); context = newcontext(action, action); pushstack(parserdata -> stack, context);

146 128 Capítulo 5. Implementación de DFBCIn En el cierre de action, se desapilará el contexto ACTION que ya debería tener la acción completa y se añadirá al array del contexto ARRAY TAG que debería encontrarse en la cima de la pila. context = (Context) popstack(parserdata -> stack); if (context -> tag!= ACTION) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } action = (Action) context -> data; freecontext(context); /* Add the complete action to the receiver array */ context = (Context) seestacktop(parserdata -> stack); if (context -> tag!= ARRAY_TAG) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } array = (Array) context -> data; addarray(array, action); La implementación del control de la etiqueta initactions sirve como primer ejemplo de aplicación del sistema descrito en el punto anterior para permitir la recogida de acciones sin afectar al código existente. La apertura de initactions consistirá simplemente en apilar un contexto ARRAY TAG con el array initactions del menú en construcción en el campo de datos. context = newcontext(array_tag, parserdata -> menu -> initactions); pushstack(parserdata -> stack, context); En el cierre de la acción sólo sera necesario desapilar en contexto ARRAY TAG y liberar la memoria ocupada por éste, pero no la ocupada por sus datos, ya que estos son el array de acciones que ya está referenciado por el menú. context = (Context) popstack(parserdata -> stack); if (context -> tag!= ARRAY_TAG) { DFBCIN_FATAL(IMPLEMENTATION_ERROR);

147 Implementación del módulo VXMLS 129 } freecontext(context); La implementación del código para timer actions es muy similar a la de initactions, con la diferencia de que para timer es necesario leer el atributo time en la apertura de la etiqueta y que esta vez el array de acciones, lógicamente, será timeactions. context = newcontext(array_tag, parserdata -> menu -> timeactions); if ((value = getattrvalue(attributes, "seconds")) == NULL) { PARSER_FATAL; } pushstack(parserdata -> stack, context); parserdata -> menu -> time = atoi(value); El código que cierra la etiqueta es el mismo que para initactions (ejecutan el mismo bloque case). La apertura de la etiqueta option supone la creación de un objeto Option vacío que se apilará dentro de un contexto OPTION, sobre el cual se apilará un contexto ARRAY TAG para recolectar las acciones que se definen dentro de la opción. option = newoption(); context = newcontext(option, option); pushstack(parserdata -> stack, context); context = newcontext(array_tag, option -> actions); pushstack(parserdata -> stack, context); En el cierre de la etiqueta, se desapilarán ambos contextos y se añadirá la opción, ya completa, al array options del menú en construcción. Los contextos serán liberados, pero no sus contenidos. context = (Context) popstack(parserdata -> stack); if (context -> tag!= ARRAY_TAG) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); }

148 130 Capítulo 5. Implementación de DFBCIn freecontext(context); context = (Context) popstack(parserdata -> stack); if (context -> tag!= OPTION) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } option = (Option) context -> data; addarray(parserdata -> menu -> options, option); freecontext(context); Por último, para implementar el control de los eventos relacionados con la etiqueta text vuelve a ser necesario apilar un contexto con espacio para almacenar la información de caracteres que será leída por la función managecharacterdata de la misma forma que para las etiquetas version y header. En el cierre de la etiqueta se desapilará el contexto TEXT apilado en la apertura y se copiará su contenido en el campo text de la opción que se está construyendo. Como tras el contexto OPTION fue apilado un contexto ARRAY TAG es necesario desapilar previamente éste para poder acceder a la opción. Una vez modificada la opción, el contexto ARRAY TAG volverá a ser colocado en su sitio. context = (Context) popstack(parserdata -> stack); if (context -> tag!= TEXT context -> data == NULL) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } strcpy(auxstring, (char *) context -> data); freecontextanddata(context); auxcontext = (Context) popstack(parserdata -> stack); context = (Context) seestacktop(parserdata -> stack); if (context -> tag!= OPTION context -> data == NULL) { DFBCIN_FATAL(IMPLEMENTATION_ERROR); } option = (Option) context -> data; strcpy(option -> text, auxstring); pushstack(parserdata -> stack, auxcontext);

149 Implementación del módulo VXMLS Interpretación de las acciones Las etiquetas utilizadas para definir las acciones que pueden ser realizadas por DFBCIn se definen en los ficheros tag-functions.c y tag-functions.h. Para implementarlas se puede suponer, como se explicó para la etiqueta action, que en el momento de abrir una etiqueta para una determinada acción, en la cima de la pila habrá un contexto ACTION con una acción vacía. Las funciones que controlan la interpretación de este tipo de etiquetas deberán dejar en la cima de la pila la acción completa, una vez cerrada la etiqueta que se está interpretando. Por supuesto, en caso de que la acción esté definida por una estructura de etiquetas anidadas, se pueden apilar nuevos contextos sobre el contexto ACTION. Por ejemplo, para interpretar la descripción de una acción BindKey se definen las siguientes funciones: startbindkeytag: Utilizará una variable de tipo BindKeyContextData para almacenar la información sobre la acción y la almacenará en un nuevo contexto que almacenará en la pila del parser. Leerá el atributo key de la etiqueta y lo escribirá en la variable almacenada en el contexto. starteventtag: Lee el argumento type de la etiqueta, crea un objeto Key (ver la sección 5.8) de acuerdo con el mismo (puede ser EXECUTE o NULL) y lo almacena en el campo correspondiente en los datos del contexto de la cima de la pila (es el contexto que se apiló en la función startbindkeytag). startkeyactionstag: En este caso se van a leer las acciones que están asociadas a la tecla, por lo que se crea un objeto Key y se apila un nuevo contexto ARRAY TAG con el array de acciones de dicho objeto en su sección de datos para recolectar las acciones. endkeyactionstag: En el cierre de la etiqueta keyactions simplemente es necesario desapilar el contexto ARRAY TAG apilado en la apertura de esta etiqueta y liberarlo. endbindkeytag: Desapilará el contexto de la cima de la pila y obtendrá de él los datos almacenados durante la interpretación de esta etiqueta (almacenados en una variable de tipo BindKeyContextData). Con esta información ya se pueden rellenar los campos de la acción que se encontrará en el contexto de la cima de la pila. context = (Context) seestacktop(parserdata -> stack); if (context -> tag!= ACTION) {

150 132 Capítulo 5. Implementación de DFBCIn } DFBCIN_FATAL(IMPLEMENTATION_ERROR); actiondata = newbindkeyactiondata(bindkeycontextdata -> inputkey, bindkeycontextdata -> key); action = (Action) context -> data; action -> actiontype = BIND_KEY_ACTION; action -> actiondata = actiondata; Cómo añadir una nueva acción? Para añadir el código necesario para interpretar una nueva acción se deberán seguir los siguientes pasos: 1. Añadir a la enumeración Tag los identificadores de las nuevas etiquetas que se vayan a utilizar para describir la acción. 2. Añadir a la función gettag las comparaciones necesarias para que pueda reconocer las nuevas etiquetas. 3. En caso de que sea necesario, definir el tipo de datos que se utilizará para almacenar la información en los bloques Context almacenados en la pila. Añadir los case que hagan falta en la función freecontextanddata para que sea capaz de liberar los contextos para las nuevas etiquetas. 4. Añadir a managestartelement el código para manejar la apertura de las nuevas etiquetas definidas. Como se explicó anteriormente, para evitar tener que modificar en exceso parser.c (y también para evitar que crezca demasiado), el control de las etiquetas utilizadas para definir acciones se hace con las funciones de tag-functions.c, por lo tanto, para una etiqueta nuevaetiqueta se creará una función startnuevaetiquetatag en tag-functions.c y se añadirá un case al switch de managestartelement para que la llame cuando se abra dicha etiqueta. 5. Añadir a manageendelement el código para manejar el cierre de las etiquetas definidas. Si es necesario realizar alguna acción, se procederá de forma similar al paso anterior creando una función endnuevaetiquetatag, en caso contrario, se añadirá un case vacío. Esta función aborta con un error IMPLEMENTATION ERROR en caso de detectar una etiqueta desconocida para evitar errores al añadir nuevas acciones.

151 Implementación del módulo VXMLS Opcionalmente, añadir el código necesario (creando una nueva función en tag-functions.c como en el caso anterior) para manejar el contenido de caracteres de alguna de las etiquetas creadas, pero normalmente valdrá con el código ya utilizado para text, header y version, que simplemente copia el contenido en el contexto de la cima de la pila Implementación de la fachada VXMLS Introducción En el fichero vxmls.c se implementan las funciones que se encargarán de realizar las peticiones a VXMLS utilizando las funciones del módulo HTTP y de interpretar sus respuestas utilizando alguno de los parsers. Durante la inicialización de este módulo se leerá del sistema de propiedades el nombre y puerto del servidor en el que está funcionando VXMLS, así como el nombre y clave que deberá utilizar DFBCIn para solicitar una nueva sesión de éste. Estos valores se guardarán ya codificados utilizando la función characterencoding (ver la sección ). Después de esto ejecutará la función vxmlslogin para crear la sesión. El principal problema se encuentra a la hora de pasar la respuesta de VXMLS a los parsers. Los parsers leen de un descriptor de fichero y, como se vio en la sección , las respuestas HTTP se escriben en un descriptor de ficheros. La solución adoptada es unir esos dos descriptores de fichero mediante un pipe. Para ello se debe ejecutar la llamada httpget en un hilo distinto al que ejecuta el parser Nuevo hilo para las peticiones Se definirá una función httpproxy que creará un pipe y un nuevo hilo de ejecución en el que utilizará la función httpget para enviar la petición a VXMLS y escribir en uno de los extremos del pipe. El otro extremo será devuelto como valor de retorno para permitir ejecutar un parser que lea de él. static int httpproxy(const char *request) { ProxyData proxydata = NULL; int pipefd[2]; pthread_t thread; if (pipe(pipefd) == -1) {

152 134 Capítulo 5. Implementación de DFBCIn } DFBCIN_FATAL(EXTERNAL_ERROR); proxydata = newproxydata(request, pipefd[1]); pthread_create(&thread, NULL, httpproxythread, proxydata); } return pipefd[0]; proxydata se utiliza para pasarle al hilo creado la cadena con la petición HTTP request y el descriptor de fichero en el que escribir la respuesta. La función httpproxythread utilizará la función httpget para enviar una petición GET al servidor VXMLS (utilizando el nombre y puerto obtenidos durante la inicialización de éste módulo). En caso de que el servidor responda con un código distinto de 200 se simulará que VXMLS ha devuelto un mensaje de error escribiendo en el pipe un mensaje de acuerdo con el DTD que especifica las respuestas de VXMLS utilizando la función writeerror. static void writeerror(const char *message, int filedes) { char errormessage[max_vxmls_error_message]; } sprintf(errormessage, "<?xml version= 1.0 encoding= iso standalone= no?>" "<!DOCTYPE vxmls SYSTEM \"/dtds/vxmls.dtd\">" "<vxmls><error>%s</error></vxmls>", message); write(filedes, errormessage, strlen(errormessage)); Una vez terminada la escritura de la respuesta, se cierra el descriptor de fichero y termina el hilo de ejecución Funciones exportadas Con ayuda de la función httpproxy la implementación de las funciones del API ofrecido por esta fachada es tan sencilla como: 1. Crear la cadena con la URL a enviar en la petición GET (en la sección 4.4 se describen las URLs a las que se debe solicitar cada posible operación):

153 Implementación del módulo VXMLS 135 Para vxmlslogin, siendo vxmlsclient el nombre que debe utilizar DFBCIn para crear la sesión y vxmlspasswd la clave que debe utilizar para identificarse: sprintf(request, VXMLS_PREFIX "login?client=%s&passwd=%s", vxmlsclient, vxmlspasswd); Para vxmlslogout, simplemente VXMLS PREFIX "logout". Para vxmlssetporperty, suponiendo escapedname y escapedvalue el nombre y el nuevo valor de la propiedad ya codificados con la función escapedencoding: sprintf(request, VXMLS_PREFIX "set_property?name=%s&value=%s", escapedname, escapedvalue); Para vxmlsgetmenu es necesario un bucle para añadir todos los argumentos. strcpy(escapedmenuname, menuname); escapedencoding(escapedmenuname); /* Get the request */ sprintf(request, VXMLS_PREFIX "get_menu?menu=%s", escapedmenuname); if (arguments!= NULL) { /* Append the parametters */ for (i = 0; i < numarrayelements(arguments); i++) { name = (char *) getarraydata(arguments, i++); value = (char *) getarraydata(arguments, i); /* Encode strings */ strcpy(escapedname, name); escapedencoding(escapedname); strcpy(escapedvalue, value); escapedencoding(value); /* Append to the request */ sprintf(request, "%s&%s=%s", request, escapedname,

154 136 Capítulo 5. Implementación de DFBCIn } } escapedvalue); 2. Hacer una llamada a httpproxy con la petición generada: filedes = httpproxy(request); 3. Utilizar el parser adecuado para interpretar la respuesta de VXMLS: Para vxmlsgetmenu se utilizará la función parsemenu y se copiarán los valores con los que fue obtenido el menú: menu = parsemenu(filedes); close(filedes); strcpy(menu -> name, menuname); menu -> arguments = arguments; addarrayreference(arguments); return menu; El resto de funciones utilizarán parsevxmlsresponse y comprobarán que el resultado devuelto por VXMLS es mensaje de confirmación. En caso de fallo en la comunicación también se obtendrá un mensaje de error, como se explicó antes, el hilo que se encarga de obtener la respuesta escribe un mensaje de error por sí mismo si no consigue contactar correctamente con VXMLS. if (parsevxmlsresponse(filedes)!= NO_ERROR) { seterrormessage(getvxmlserrormessage()); DFBCIN_FATAL(VXMLS_ERROR); } close(filedes); Implementación del Módulo gráfico Introducción El módulo gráfico se implementará como una biblioteca dinámica para permitir que se puedan intercambiar distintos módulos de este tipo sin necesidad de recompilar la aplicación.

155 Implementación del Módulo gráfico 137 El API que debe implementar la biblioteca para poder ser utilizada como módulo gráfico se puede ver en el apéndice B. En las siguientes secciones se explicarán los pasos que se han seguido en la implementación del módulo gráfico con la ayuda DirectFB. También se ha hecho otra implementación para algunas pruebas que utiliza la consola de texto en lugar del hardware gráfico Estructuración del código La implementación de la fachada es idéntica para los dos módulos gráficos implementados, por lo que el código se organizará en tres directorios, un directorio Common en el que se almacenará el fichero graphics.c y las cabeceras interface-draw.h, video.h, graphics-init.h y event-catcher.h que definen las diferentes clases utilidad que componen el módulo gráfico. Las cabeceras anteriores serán implementadas con el correspondiente fichero.c en los directorios DFB para el módulo gráfico completo y Character para el módulo gráfico de pruebas La fachada graphics.c En el fichero graphics.c se implementan todas las funciones definidas por el API del módulo gráfico. Excepto las funciones de creación y destrucción, el resto delegan directamente en la clase correspondiente: InterfaceDraw para las operaciones de dibujo, EventCatcher para el método testinput y Video para las operaciones de control de vídeo. La función graphicsinit llamará a la funciones de inicialización de los subsistemas que componen este módulo. void graphicsinit(int argc, char **argv) { specificinit(argc, argv); interfacedrawinit(); videoinit(); } specificinit se define en el fichero graphicsinit.c de cada uno de los dos módulos gráficos implementados, para permitir realizar operaciones específicas de inicialización. graphicsdeinit llama a las funciones de destrucción de los subsistemas inicializados por graphicsinit.

156 138 Capítulo 5. Implementación de DFBCIn void graphicsdeinit(void) { interfacedrawdeinit(); videodeinit(); specificdeinit(); } specificdeinit tiene el mismo cometido que specificinit: permitir operaciones específicas de destrucción La inicialización de DirectFB Para inicializar el módulo gráfico que utiliza DirectFB, specificinit deberá: 1. Inicializar DirectFB llamando a la función DirectFBInit. 2. Crear la interfaz primaria llamando a DirectFBCreate. 3. Utilizando la interfaz primaria, crear la superficie primaria y el buffer de eventos de entrada. La función specificdeinit deberá liberar los recursos creados durante la inicialización por specificinit Control de eventos de entrada En el fichero event-catcher.c se implementa la función testinput que deberá detener la ejecución hasta que se detecte que el usuario ha pulsado una de las teclas soportadas (todas las del mando a distancia y alguna del teclado para facilitar las pruebas). El control de entrada utilizando DirectFB se puede realizar mediante dos métodos: con o sin buffer de eventos. Para la este proyecto se utilizará el control de entrada utilizando buffer de eventos, de esta forma no es necesario implementar mecanismos adicionales para recordar los eventos que aún no fueron atendidos. Para esta aplicación sólo interesan los eventos de entrada (en un buffer de eventos genérico de DirectFB también se almacenan otro tipo de eventos, por ejemplo eventos relacionados con la gestión de ventanas), estos eventos se pueden manejar utilizando un tipo especial de buffer de eventos creado con la función CreateInputEventBuffer de la interfaz principal.

157 Implementación del Módulo gráfico 139 Un buffer de eventos de entrada de DirectFB puede detectar varios tipos de eventos: Eventos de teclas. Eventos de ejes. Eventos de botones. El buffer de eventos de entrada utilizado sólo deberá preocuparse de los eventos de teclas, que pueden ser o bien eventos de pulsación de tecla DIET KEYPRESS, o bien eventos de liberación de tecla DIET KEYRELEASE. Para controlar el mando a distancia se utilizará la herramienta LIRC [46]. Esta herramienta está soportada directamente por DirectFB, de forma que los eventos detectados por LIRC generarán eventos de pulsación y liberación de teclas en las aplicaciones que utilizan DirectFB. Para ello, en el fichero de configuración de LIRC se deben nombrar los códigos reconocidos para cada tecla del mando a distancia con un nombre equivalente a alguna de las teclas definidas en el fichero directfb-keynames.h sin el prefijo DIKS. Por ejemplo, para la tecla play del mando a distancia, se añade la línea PLAY 0x CCB3 en el fichero lircd.conf para asociar la tecla PLAY al código generado con la pulsación de play en el mando a distancia. En las aplicaciones DirectFB se detectarán eventos DIKS PLAY para esa tecla. Un problema que presenta el uso del mando a distancia es el hecho de que éste no genera un único evento DIET KEYPRESS cuando se pulsa la tecla y un evento DIET KEYRELEASE cuando se suelta la tecla, sino que está generando eventos como si se pulsara la tecla intermitentemente. Esto provoca que el control de la interfaz se haga incómodo, ya que ante una pulsación de una tecla puede comportarse como si se pulsara varias veces la misma tecla. Para solucionar este problema, se descartarán los eventos que se repitan en un determinado intervalo de tiempo. Utilizando el buffer de eventos proporcionado por DirectFB, la implementación de la función testinput es sencilla: 1. Llamar a la función waitforevent del buffer de eventos para detener la ejecución hasta que haya un evento disponible. 2. Obtener el evento detectado llamando a la función getevent del buffer de eventos.

158 140 Capítulo 5. Implementación de DFBCIn 3. Comprobar si el evento detectado es relevante para la aplicación: a) Comprobar que se trata de la pulsación de una tecla. b) Comprobar que la tecla pulsada es alguna de las soportadas por la aplicación. c) Obtener el valor InputKey utilizado por la aplicación para identificar a esa tecla. Para esto se utilizará una tabla en la que se relacionan los eventos DFBInputEvent con las teclas InputKey. 4. Filtrar el caso de que un mismo evento se repita en un pequeño intervalo de tiempo. 5. En caso de que se haya obtenido un evento válido se devuelve, en otro caso se vuelve al paso uno Impresión de menús y texto DirectFB (ver la sección 2.4) define un tipo de interfaz IDirectFBSurface que representa una superficie en la que realizar operaciones gráficas tales como copiar el contenido de otras superficies, dibujar rectángulos o líneas, imprimir texto, etc. La superficie mostrada en pantalla es la conocida como superficie primaria. Las superficies pueden dotarse de un sistema de doble buffer, las operaciones ejecutadas sólo se harán visibles cuando se ejecute la operación Flip de la superficie, que vuelve visible el buffer invisible (back buffer) e invisible el buffer visible (front buffer). Esto es útil en la superficie primaria, porque de esta forma se puede sincronizar la operación Flip con el refresco del monitor evitando los efectos desagradables que surgen si se cambia el contenido de la memoria de vídeo sin tener en cuenta este factor. InterfaceDraw proporciona operaciones para cargar y descargar un menú, cargar y descargar una serie de líneas de texto y modificar la forma en la que se dibujan los menús (si se muestra o no un marco rodeándolos). La función interfacedrawflipbuffer dibujará los elementos cargados en caso de que los haya. En la inicialización de este módulo se cargarán las fuentes e imágenes que se van a utilizar para generar la interfaz con el usuario. DirectFB define la interfaz IDirectFBFont para representar una fuente, las imágenes se almacenan en superficies. Para cargar los elementos utilizará la interfaz IDirectFBImageProvider para

159 Implementación del Módulo gráfico 141 leer los ficheros de imagen y la función CreateFont de la interfaz primaria para crear las fuentes dado un tamaño y un fichero True Type. También se creará una variable de estado en la que almacenar el menú y el texto cargados y una bandera para indicar si se debe o no dibujar un marco rodeando al menú. La función de destrucción deberá liberar todos los recursos anteriormente creados por la función de inicialización. La función drawmenu bloqueará el menú cargado para asegurar que no se modificará la opción actualmente seleccionada durante el proceso de representarlo gráficamente. Para dibujar el menú se escribirá el campo header a modo de título, las opciones se dibujarán en cinco líneas. En caso de que haya más de cinco opciones, se dibujará la opción actualmente seleccionada en la línea del centro, las opción siguiente y la anterior en la cuarta y segunda línea y unas flechas arriba y abajo en la primera y quinta línea. Dibujar una opción supone escribir su campo text. La opción actualmente seleccionada se dibujará en color amarillo y el resto en color azul. La función drawtext simplemente escribirá las líneas de texto cargadas. Para centralizar el control sobre la superficie primaria, será InterfaceDraw la única encargada de ejecutar la operación Flip sobre la misma. Para ello se implementa la función interfacedrawflipbuffer, que ejecuta las siguientes operaciones: 1. En caso de que su argumento showbackground sea distinto de 0 copiará la superficie con la imagen de fondo en el buffer invisible. 2. Si hay un menú cargado, dibujará dicho menú en el buffer invisible. 3. Si hay texto cargado, imprimirá dicho texto en el buffer invisible. 4. Por último ejecutará la operación Flip sobre la superficie primaria durante el próximo barrido vertical: DFBCHECK(primary -> Flip(primary, NULL, DSFLIP_WAITFORSYNC)); Reproducción de vídeo DirectFB es capaz de reproducir distintos formatos de vídeo utilizando su sistema de proveedores (ver la sección 2.4). Los vídeos se cargan creando una interfaz IDirectFBVideoProvider, utilizando la función CreateVideoProvider de la

160 142 Capítulo 5. Implementación de DFBCIn interfaz principal. DirectFB detecta el formato de vídeo y carga la implementación necesaria de proveedor de vídeo. En las pruebas se comparó la reproducción de vídeos en formato MPEG con la reproducción de vídeos en formato AVI, obteniéndose mejores resultados en el segundo caso. El proveedor de vídeo utilizado para reproducir ficheros AVI usa la biblioteca avifile [47]. La versión proporcionada con DirectFB estaba implementada sobre una versión antigua de avifile y presentaba ciertos problemas que serán comentados posteriormente, pero que fueron solucionados, en parte, adaptando la implementación del proveedor para que utilizará una versión más moderna de avifile. El procedimiento que se sigue para la carga y reproducción de un vídeo es el siguiente: Con una llamada a la función videoload se carga un fichero de vídeo de forma que quede listo para ser reproducido. El proceso de carga de un vídeo es el siguiente: 1. Crear el proveedor de vídeo sobre el fichero de vídeo a reproducir. 2. Obtener la información sobre la resolución del vídeo a reproducir y utilizarla para crear una superficie en la que reproducirlo. 3. Crear un rectángulo del máximo tamaño posible (respetando la relación ancho/largo del vídeo) en el que se va a copiar cada frame en la superficie primaria. La función videoplay iniciará la reproducción del vídeo en la superficie creada por videoload. Para ello utilizará la función PlayTo del proveedor de vídeo creado por videoload: videoprovider -> PlayTo(videoProvider, videosurface, NULL, videocallback, NULL); El proveedor llamará a la función videocallback cada vez que esté disponible un nuevo frame. Esta función será utilizada para llamar a la función instalada por videosetnewframecallback. La función videostop detendrá la reproducción de vídeo utilizando la función Stop del proveedor de vídeo.

161 Implementación del Módulo gráfico 143 La función videoblit copia el frame actual en el buffer no visible de la superficie primaria (ver la sección ). Esta función será llamada por Interface cada vez que se notifique que hay un nuevo frame. La función videounload elimina el proveedor de vídeo y libera la superficie utilizada para reproducir el vídeo. Las funciones para obtener la posición actual y para mover la reproducción a una determinada posición utilizan las funciones que proporciona el proveedor de vídeo: GetPos y SeekTo Detección del final de la reproducción La interfaz IDirectFBVideoProvider no tiene ninguna función que permita detectar el final del vídeo directamente, sin embargo, en la definición de la acción VideoPlay, se especifica un array de acciones que se deberán ejecutar al terminar el vídeo. Por lo tanto, es necesario detectar el final del vídeo de alguna forma y ejecutar la función instalada por videosetvideoendcallback. Para ello, es necesario crear un nuevo hilo de ejecución que monitorice el estado del proveedor de vídeo durante la reproducción. La función de inicialización creará dicho hilo (observerthread) y una variable de estado para comunicarse con él de forma similar a la explicada para Interface e InterfaceInput en las secciones y La primera opción que se barajó fue la de comprobar cada cierto tiempo que el valor devuelto por la función GetLength y la función GetPos del proveedor de vídeo no era el mismo, pero se comprobó que la función GetPos llamada al final del vídeo no siempre devolvía la última posición. La solución que se adoptó definitivamente fue comprobar cada cierto tiempo que el valor devuelto por GetPos había cambiado, de no ser así, se puede asumir que el vídeo está detenido en el final. Esta solución obliga a disponer de una bandera VST PLAY que se active sólo cuando el vídeo se está reproduciendo para evitar que el hilo detecte el final del vídeo cuando lo que realmente está sucediendo es que el vídeo está detenido debido a una llamada a videostop. También se necesita otra bandera VST SEEK que se activará en caso de que se ejecute la función videogotovideoposition, para advertir que no se tenga en cuenta la próxima comparación ya que podría darse la casualidad de que se ejecutara sobre la misma posición. El ciclo de ejecución del hilo observerthread será como sigue:

162 144 Capítulo 5. Implementación de DFBCIn 1. Esperar N segundos. 2. Bloquear la variable de estado. 3. Si está activa la bandera VST SEEK desactivarla y guardar la posición actual en el campo lastframe del estado. 4. Si está activa la bandera VST PLAY: Si el valor devuelto por GetPos es igual a lastframe entonces se desactiva VST PLAY y se llama a la función instalada para avisar del final del vídeo por videosetvideoendcallback. En otro caso, poner el valor devuelto por GetPos en lastframe. 5. desbloquear la variable de estado y volver a 1. Para que este hilo funcione correctamente es necesario modificar algunas de las funciones de video.h (las operaciones sobre la variable de estado se harán siempre bloqueando el semáforo primero): videoplay debe activar la bandera VST PLAY. videostop debe desactivar la bandera VST PLAY. videogotovideoposition debe activar la bandera VST SEEK en caso de que se salte a una posición anterior Módulo de pruebas La implementación del módulo gráfico de pruebas consiste simplemente en los ficheros: event-catcher.c: Se hace un control de la entrada utilizando las funciones de la biblioteca stdio. video.h: Lo único que hacen todas las operaciones es escribir un mensaje en la consola indicando que fueron llamadas. graphics-init.c: Las implementaciones de las funciones specificinit y specificdeinit son vacías. interface-draw.c: Tiene un comportamiento similar al de su homólogo en la implementación seria. Las funciones interfacedrawblitbackground y intefacedrawsetbox sólo muestran mensajes para indicar que fueron ejecutadas, los menús se dibujan con cadenas de texto como, por ejemplo:

163 Etapas de codificación "Menu Principal" *(0) Axustes (1) Películas Las líneas de texto, simplemente, se muestran en la consola Sistema de propiedades El sistema de propiedades lee el contenido de un fichero local y lo almacena en un array que contiene datos del tipo Property. El tipo Property apunta a una estructura con dos campos: name: Nombre de la propiedad. value: Valor de la propiedad. Las funciones getproperty y setproperty se implementan asegurando la sincronización mediante la implementación de un sistema de lectores-escritores. Varios hilos pueden estar leyendo una misma propiedad concurrentemente, pero un hilo puede modificar una propiedad sólo en caso de que no haya ningún otro hilo accediendo a la misma. Esto fue utilizado durante algunas etapas del desarrollo, pero en el sistema final el sistema de propiedades sólo se utiliza para almacenar datos estáticos, las propiedades cambiantes serán controladas por VXMLS Etapas de codificación El desarrollo final se consiguió después de pasar por los siguientes incrementos Desarrollo del núcleo de la aplicación En este primer incremento se pretende obtener un sistema con la funcionalidad mínima. Para ello se desarrollan los siguientes módulos: Las acciones NextMenu y PreviousMenu, para permitir la navegación por el sistema de menús.

164 146 Capítulo 5. Implementación de DFBCIn El parser de menús. En este incremento el parser será capaz de interpretar las etiquetas header, version, option, action, previousmenu y nextmenu. El control de entrada sólo reconoce la pulsación de las teclas arriba, abajo y SEL. Por ahora no se utiliza el mando a distancia. Como aún no se dispone de las acciones BindKey ni ChangeOption, Interface se encargará de cambiar la opción seleccionada cuando se detecte la pulsación de las teclas arriba o abajo y de mandar ejecutar las acciones de la opción seleccionada en cuanto se detecte la pulsación de ENTER. En este incremento InterfaceDraw sólo será capaz de mostrar menús. No hay módulo VXMLS, la descripción de los menús se lee de ficheros locales, que se pasan directamente al parser. Tras esto se obtiene una aplicación que muestra una serie de menús gráficos descritos por ficheros XML, permitiendo navegar por ellos a través de las opciones mostradas, utilizando las teclas arriba, abajo y SEL Reproducción básica de vídeo En este iteración se añadirán las acciones que permitan iniciar la reproducción de un vídeo. Implementación de las acciones PlayVideo, StopVideo, ResumeVideo y UnloadVideo. Por ahora la acción PlayVideo no contempla las acciones de finalización. Modificación del parser para que puedea interpretar las etiquetas que definen estas nuevas acciones. Implemetación de Video en el módulo gráfico. Por ahora no es necesario detectar la finalización del vídeo. En esta iteración se obtiene una aplicación que ya cumple con los requisitos mínimos que se exigen en la especificación. Muestra una interfaz definida por ficheros XML y es capaz de reproducir ficheros de vídeo.

165 Etapas de codificación Pruebas en el Set Top Box Hasta este paso se hizo el desarrollo en un PC. En esta iteración se harán las pruebas en el Set Top Box y se desarrollará el control del mando a distancia. Pruebas de rendimiento el el Set Top Box, en este paso se realizaron las optimizaciones explicadas en el apartado Instalación de LIRC y comprobación de su funcionamiento con la aplicación. Por ahora, las únicas teclas utilizables siguen siendo arriba, abajo y ENTER. Tras esto ya se tiene el sistema completo, funcionando de forma básica en la televisión y con el mando a distancia como sistema de entrada Varias mejoras En esta iteración se terminará de desarrollar el sistema de entrada, se incorporará la temporización, las acciones de personalización y se completará la implementación del sistema de vídeo. Para completar el sistema de entrada: Implementación completa de testinput para que sea capaz de detectar la pulsación de todas las teclas del mando a distancia. Implementación de la acción BindKey para permitir la asociación de teclas con eventos. Implementación del mecanismo de inicialización de menús, de forma que cuando se cargue un menú en Interface se ejecuten las acciones del campo initactions de dicho menú. Este campo se hace imprescindible, ya que ahora por defecto las teclas están vinculadas al evento NULL. Implementación de la acción ChangeOption, ya que ahora ya se puede asociar a una tecla. Modificación del parser para que sea capaz de interpretar la descripción de estas nuevas características. Para implementar la temporización se debe modificar el método waitforactions de Interface para que devuelva las acciones del campo timeactions del menú actual en caso de que finalice la temporización. También se deberá modificar el parser para que pueda interpretar el campo timer de los documentos XML.

166 148 Capítulo 5. Implementación de DFBCIn Para implementar la posibilidad de personalización se crea una nueva acción SetProperty, que, por ahora, posibilitará definir y modificar los valores para ciertas propiedades, como por ejemplo definir el lenguaje a utilizar. Esta acción trabajará sobre el sistema de propiedades local descrito en En el sistema de vídeo se añade el control de finalización, para lo que es necesario modificar también la acción PlayVideo y el parser para que interprete el contenido de la etiqueta loadvideo como el conjunto de acciones a ejecutar en caso de que finalice la reproducción. También se añade una nueva acción SeekVideo para permitir reposicionar la reproducción. De nuevo, es necesario modificar el parser para que pueda interpretar las etiquetas que definen esta acción Comunicación HTTP En esta iteración se implementará el sistema de comunicación HTTP, pero aún no se utilizará con VXMLS, ya que no está desarrollado todavía, sino que obtendrá los ficheros de un servidor HTTP estático. Una vez finalizada esta iteración ya se tendrá un sistema capaz de mostrar una interfaz definida remotamente y de reproducir vídeo, interactuando con el usuario a través de una televisión y un mando a distancia. En este punto se detiene temporalmente el desarrollo de DFBCIn y se comienza a implementar VXMLS Integración con VXMLS En este incremento se completa el desarrollo el módulo VXMLS para que acceda a las URLs del mismo para solicitar los menús o cambiar las propiedades de personalización. Para esto es necesario modificar también las acciones ChangeProperty y NextMenu. Al utilizar VXMLS como servidor se implementan dos nuevas características: los parámetros para solicitar menús y la selección de lenguaje. La selección de lenguaje consiste simplemente en modificar la propiedad de personalización language utilizando una acción SetProperty, pero para poder definir correctamente la interfaz, es necesario implementar una nueva acción Re-

167 Etapas de codificación 149 loadmenu para permitir volver a solicitar el menú principal en el nuevo idioma. Para facilitar la generación de menús, VXMLS acepta parámetros cuando se le solicita un determinado menú. Para implementar esta característica es necesario modificar la acción NextMenu. Será también necesario modificar el parser para que pueda interpretar la descripción de la acción ReloadMenu y los parámetros que ahora se incluyen en las descripciones de las acciones NextMenu Integración con VoDKA El sistema de vídeo utilizado hasta ahora es capaz de reproducir vídeos desde un fichero local, pero el Set Top Box desarrollado debe reproducir vídeo obtenido de un servidor de streaming. Es necesario, por tanto, utilizar un mecanismo que permita a DFBCIn acceder a este tipo de medios. En [37] se desarrolla un sistema de ficheros virtual que permite a los reproductores un acceso sencillo a los medios obtenidos mediante la descarga de streaming. Utilizando este sistema no es necesario realizar ninguna modificación a la aplicación DFBCIn, simplemente se debe montar un sistema de ficheros virtual y acceder a los medios disponibles de la misma forma que se accedía a los ficheros locales Reproductor Mp3 y acciones de texto Finalmente se añaden las acciones LoadMp3, PauseContinueMp3, KillMp3- Player, LoadText y UnloadText. Para ello es necesario implementar la clase Mp3- Player y llevar a cabo pequeñas modificaciones en la librería gráfica. Como en los casos anteriores, se deberá modificar el parser de menús para que pueda interpretar las nuevas etiquetas y el servidor VXMLS para que pueda generarlas.

168

169 Capítulo 6 Implementación de VXMLS Índice General 6.1. Introducción Generalidades sobre Erlang/OTP Cómo funciona Inets? Cómo funciona Mnesia? Servidores genéricos Estructura de la aplicación VXMLS Tipos de datos Control de errores Capa Modelo Tipos de datos Administración de la base de datos Funciones de la fachada Capa Vista Capa Controlador Generación de la respuesta HTTP Traducción de mensajes Fachada Creación y destrucción de sesiones Propiedades de personalización Generación de menús Composición de objetos Menu

170 152 Capítulo 6. Implementación de VXMLS Menús definidos Ejemplos de vxmls get menu Extensibilidad Introducción Generalidades sobre Erlang/OTP El modelo de programación de Erlang se basa en la creación de procesos que se ejecutan concurrentemente y que se comunican entre ellos mediante paso de mensajes. El código se estructura en módulos, cada uno de los cuales implementa una serie de funciones. Un módulo puede exportar funciones que serán accesibles al resto, las funciones no exportadas son locales y no afectan para nada a los demás módulos. Un proceso Erlang es una unidad de computación aislada, que coexiste concurrentemente con otros procesos en el sistema. Un proceso se crea utilizando la BIF spawn a la que se le pasa el nombre de un módulo, una función de dicho módulo y una lista de argumentos. El proceso creado finalizará cuando termine la ejecución de la función. Estos procesos se ejecutan dentro de un nodo Erlang, cada nodo Erlang ocupa un único proceso del sistema operativo. Erlang/OTP [4] también se define el concepto de aplicación. Una aplicación es un paquete de recursos, tales como nombres registrados, módulos y procesos. La aplicación VXMLS, utilizará, a su vez, algunas aplicaciones que forman parte del entorno Erlang/OTP: Inets [39] que es un contenedor de servidores para Internet, Mnesia [40] que es un sistema gestor de bases de datos distribuidas y Mnemosyne [41] que es una interfaz de consulta para Mnesia Cómo funciona Inets? Inets incluye una implementación de un servidor web compatible con el protocolo HTTP 1.1 [35]. Para comunicarse con aplicaciones externas el servidor implementa CGI [48] y ESI (Erlang Scripting Interface). ESI proporciona una interfaz eficiente para acceder a funciones Erlang, se recomienda la utilización de ESI sobre la utilización de CGI por razones de eficiencia, ya que CGI necesita que el servidor cree un nuevo proceso de sistema

171 Introducción 153 operativo. ESI imita a CGI pero sin el sobrecoste de crear un nuevo proceso, una URL puede llamar a una función Erlang de acuerdo con la siguiente sintaxis: /PathInfo) El nodo Erlang en el que se ejecuta Inets deberá tener acceso a un módulo Mod con una función Func con dos argumentos. Si un cliente accede a la URL anterior se ejecutará Func(Env,Input), donde Env contiene información sobre el cliente e Input la cadena QueryString o PathInfo de acuerdo con la especificación [48], la función deberá devolver una cadena de texto siguiendo esta misma especificación. Para implementar VXMLS se utilizará el sistema ESI, las funciones utilizadas para recibir las llamadas de Inets serán las de la fachada VXMLSFacade (ver la sección 4.6.5). En el fichero de configuración de Inets se debe especificar que URLs se utilizan de interfaz con ESI y a qué módulos pueden acceder. Para VXMLS, estas funciones se definirán en el módulo vxmls, y únicamente se utilizará una URL para acceder éstas. Suponiendo que se estén ejecutando unas pruebas con el servidor en el puerto 8080 de la máquina local: Donde Mod debe ser vxmls y Func podrá ser alguna de las siguientes: login, logout, get menu o set property. En la sección 4.4 se explican las peticiones que se pueden enviar a VXMLS Cómo funciona Mnesia? El acceso a una base de datos Mnesia desde una aplicación Erlang es sencillo, una vez arrancada la aplicación sobre un nodo, se pueden utilizar las funciones exportadas por el módulo mnesia para manipular las tablas. Para realizar consultas complejas se debe utilizar Mnemosyne que permite escribir consultas embebidas en el código Erlang utilizando una construcción llamada query list comprehensions. La sintaxis es la siguiente: query [ <patrón> <cuerpo> ] end Por ejemplo:

172 154 Capítulo 6. Implementación de VXMLS query [ Empleado Empleado <- table(empleado), Empleado.departmento = ventas ] end Servidores genéricos Erlang/OTP define el concepto de comportamiento (behaviour) como una formalización de patrones de diseño que pueden ser utilizados para programar algunos problemas genéricos. Un módulo que utilice un comportamiento deberá exportar ciertas funciones que que serán llamadas por el sistema mientras el proceso se ejecuta. En Erlang/OTP, una aplicación cliente-servidor puede ser programada utilizando el comportamiento gen server, este comportamiento será utilizado para implementar dos servidores en la aplicación VXMLS, el servidor vxmls que representa a la aplicación en sí (cuando termina la ejecución del proceso vxmls termina la ejecución de la aplicación) y el servidor vxmls lang, que mantendrá tablas con los posibles mensajes a mostrar traducidos a los diferentes idiomas soportados. Un servidor genérico se crea con la función start del módulo gen server que crea un proceso con el nombre del servidor y lo mantiene en ejecutándose hasta que se elimina utilizando alguno de los mecanismos establecidos para detener el servidor Estructura de la aplicación VXMLS El código de la aplicación VXMLS se estructura en los siguientes módulos: vxmls: Contiene las funciones para inicializar y detener la aplicación (start y stop) y las funciones que atenderán las peticiones de Inets. vxmls lib: En este módulo se agrupan funciones de diversa índole. vxmls xml: Este módulo exporta funciones para la generación de documentos XML. vxmls menu: Este módulo exporta funciones para la generación de objetos Menu. vxmls db: Exporta las funciones para acceder a la capa modelo de VXMLS y una función para inicializar la base de datos.

173 Introducción 155 vxmls lang: Exporta funciones para obtener mensajes traducidos a diversos idiomas. vxmls conf : Exporta funciones para acceder al fichero de configuración de VXMLS. vxmls properties: Exporta las funciones necesarias para atender a la petición set property. vxmls login: Exporta las funciones necesarias para atender a las peticiones login y logout. vxmls menu dispatcher: Exporta las funciones necesarias para atender a la petición get menu. Además de estos, cada menú es generado por un módulo, esto permite añadir nuevos menús sin necesidad de modificar ni recompilar el código existente. Para generar un menú llamado, por ejemplo, foo menu, será necesario crear un nuevo módulo vxmls foo menu. Como norma general, todos los módulos creados con este objetivo tendrán un nombre de forma vxmls *** menu Tipos de datos Para representar los objetos necesarios en Erlang se siguieron distintas aproximaciones: Los objetos valor [44] se representan definiendo un registro con los campos necesarios. Para ocultar la estructura interna del tipo se definirán las funciones necesarias para acceder a sus campos en un único módulo. Por ejemplo: la clase Menu 1 se implementa definiendo un registro menu y el módulo vxmls menu con las funciones para manipularlo. Las clases utilidad se representan con un módulo que exporte las funciones requeridas. Los objetos Singleton se representan utilizando el comportamiento Erlang gen server. 1 en la forma en que se utiliza en VXMLS, ver sección 4.6.2

174 156 Capítulo 6. Implementación de VXMLS Control de errores La filosofía de control de errores de Erlang consiste en asumir siempre que los argumentos recibidos por una función son correctos, es decir, no hacer control de errores de forma explícita. Si en algún momento una función llega a una situación inesperada, el proceso que ejecuta esta función debe morir. Se pueden establecer jerarquías de procesos en las que procesos supervisores monitoricen la ejecución de procesos trabajadores, cuando un trabajador muere debido a un error, un supervisor detecta el fallo y actúa en consecuencia para corregir el error. En caso de que se vaya a utilizar una función susceptible de provocar un error, pero que no necesariamente debe provocar la muerte del proceso, el código se puede ejecutar dentro de un bloque catch que devolverá la tupla { EXIT, Razon} en caso de que el código que contiene alcance algún punto en el que el proceso finalizaría en circunstancias normales. En la aplicación desarrollada los procesos pueden morir debido a diversas causas, identificadas por los siguientes valores de Razon: {open, Atom, File}: Error al abrir un fichero. Atom identifica la causa del error y File es el nombre del fichero. {format, Reason, File}: Un fichero leído no tiene el formato esperado. Reason contiene una descripción del error y File es el nombre del fichero. {not found, Key}: No se ha encontrado un valor almacenado para la clave Key. bad request: Se ha recibido una petición HTTP no válida. incorrect password: La clave del Set Top Box no es correcta. cookie not valid: La cookie asociada al Set Top Box no es válida. not logged in: El Set Top Box no tiene asociada una sesión. no home argument: La aplicación se ha arrancado sin el argumento home, necesario para acceder a algunos ficheros. {unknown item, {Name, Value}}: Se ha proporcionado un valor desconocido o una propiedad desconocida. Name indica el nombre de la propiedad y Value el valor.

175 Capa Modelo 157 {database error, Reason}: Error alguna operación realizada sobre la base de datos. Reason puede tomar alguno de los siguientes valores: {not found, Key}: No se encontró el registro con la clave Key. {reference constraint, Table, Key}: La clave Key utilizada como referencia a un registro de la tabla Table no está presente en ésta. {already exists, Key}: Ya existe un objeto con clave Key. user not found: El usuario no se ha encontrado. Cualquier otro error será considerado desconocido a la hora de notificarlo Capa Modelo Tipos de datos Las funciones utilizadas para insertar datos en Mnesia utilizan registros para representar las tuplas de las tablas. Esto implica que en una tabla de la base de datos se puede almacenar cualquier tipo de dato Erlang. Normalmente sólo se almacenarán cadenas de texto o átomos, pero en algunos casos también se utilizarán tuplas para representar claves múltiples En la mayoría de los casos un objeto del dominio se relacionará con una tabla de la base de datos, excepto la tabla shown movie que no representa ningún objeto, sino la relación N a N entre user y movie y el objeto TranslatedMovie, que no representa ninguna tabla de la base de datos. En el fichero vxmls tables.hrl se definen los registros que se utilizarán para almacenar los datos sobre los diferentes objetos del dominio y las tablas de la base de datos: set top box: Contiene los campos necesarios para identificar a un Set Top Box cliente: id: Cadena de texto que identifica unívocamente al cliente. passwd: Contiene la clave encriptada. cookie: Referencia a la cookie que identifica la sesión creada para este Set Top Box. user: Referencia al usuario activo para este Set Top Box cookie: Representa a una cookie utilizada para identificar una sesión.

176 158 Capítulo 6. Implementación de VXMLS string: La cadena de texto que define la cookie. id: Referencia al Set Top Box para el que esta cookie define una sesión. language: Representa un idioma. id: Identificador ISO del idioma. name: Nombre del idioma. movie: Representa una película. id: Átomo utilizado para identificar a la película. file: Fichero que contiene el vídeo. genre id: Referencia al género de la película. year: Año en el que fue publicada. new: Si es true indica que la película es un estreno. movie info: Contiene datos textuales sobre una determinada película que deben ser traducidos a los diferentes idiomas soportados. id: Clave compuesta por una referencia a la película y otra al idioma. synopsys: Lista de cadenas de texto con un resumen de la película. title: Título de la película. genre: Representa un género. id: Clave compuesta por un átomo que identifica al género y una referencia a un idioma. name: Nombre traducido del género. user: Información sobre un usuario de un determinado Set Top Box. id: Clave compuesta por el nombre del usuario y una referencia al Set Top Box. lang id: Referencia al idioma seleccionado por el usuario. shown movie: Representa la tabla utilizada para almacenar la relación entre un usuario y las películas que ha visto. id: Clave compuesta por una referencia al usuario y una referencia al Set Top Box. movie id: Referencia a la película.

177 Capa Modelo 159 translated movie: Agrupa información sobre una determinada película traducida a un cierto idioma. No representa a ninguna tabla de la base de datos. id: El átomo identificador de la película. file: El fichero en el que se encuentra el vídeo. genre id: Referencia al género de la película. year: Año en el que fue publicada. synopsys: Resumen. title: Título Administración de la base de datos Como no se ha desarrollado ninguna herramienta de administración, en el módulo vxmls db se exporta una función init que creará todas las tablas necesarias e introducirá los datos indicados por un fichero de configuración. El fichero de configuración es un fichero de texto en el que se escriben términos Erlang separados por puntos. El formato utilizado para esta aplicación es el siguiente: {NombreDeTabla1, ListaDeTuplas1}. {NombreDeTabla2, ListaDeTuplas2}.... Utilizando la función read del módulo vxmls conf se obtiene una lista con todas las tuplas que definen el contenido de las diferentes tablas. Tras esto se almacenarán esas tuplas en las tablas recién creadas Funciones de la fachada Acceso a datos Las funciones que permiten el acceso a los datos del modelo están implementadas en el módulo vxmls db. La mayoría de ellas utilizarán el API de Mnesia para manipular los datos persistentes almacenados en la base de datos, pero también se exportan las funciones que permiten el acceso a los datos almacenados en los objetos valor que devuelven algunas operaciones. De esta forma se aisla la representación interna de dichos objetos valor del resto de módulos. Las funciones exportadas se pueden clasificar en cuatro categorías:

178 160 Capítulo 6. Implementación de VXMLS Funciones de acceso a datos: Devuelven datos almacenados en la base de datos. Funciones de edición datos: Modifican el valor de un campo de alguna tabla de la base de datos. Funciones de inserción de datos: Añaden nuevas tuplas a la base de datos. Funciones de acceso a los campos de un objeto valor: Devuelven el valor de un atributo de una variable de alguno de los tipos definidos internamente para agrupar información relacionada. Una función que se escapa de esta clasificación es la función set property, que se comporta de forma diferente según la propiedad a modificar: user: Cambia el usuario referenciado en un Set Top Box. language: Cambia el idioma referenciado en un usuario. shown movie: Añade un nuevo registro a la tabla shown movie en caso de que dicho registro aún no exista Transacciones El procedimiento general para ejecutar una transacción en Mnesia es el siguiente: 1. Crear una función de nivel superior que ejecute las operaciones que conformen la transacción. Por ejemplo, para obtener el registro correspondiente al usuario activo en un Set Top Box dado el identificador del Set Top Box: F = fun () -> [SetTopBox] = mnesia:read({set_top_box, SetTopBoxId}), [User] = mnesia:read({user, {SetTopBoxId, SetTopBox#set_top_box.user}}), User end 2. Ejecutar la función transaction del módulo mnesia que toma como argumento una función de nivel superior y la ejecuta de forma atómica dentro de una transacción. En caso de que se produzca algún error aborta la transacción y ejecuta un rollback. Esta función puede devolver:

179 Capa Modelo 161 {atomic, Result}: En caso de éxito Mnesia devuelve en Result el resultado devuelto por la función ejecutada por transaction. {aborted, Reason}: En caso de error Mnesia devuelve esta tupla. Reason representa la razón del error. Para ejecutar las transacciones sobre Mnesia de acuerdo con la filosofía adoptada para el control de errores en VXMLS se define mnesia transaction, que toma como argumento la función de nivel superior que define la transacción y comprueba que el resultado es correcto, en caso de que transaction devuelva {aborted, Reason} el proceso termina con el error {database error, Reason}, si devuelve {atomic, Result} devuelve Result. Una transacción puede ser abortada explícitamente ejecutando la función abort del módulo mnesia a la que se le pasa un valor que será la razón devuelta por transaction Funciones de acceso a datos Este tipo de funciones buscarán un dato en una tabla siguiendo un determinado criterio. Las búsquedas en las tablas de Mnesia se pueden hacer de varias formas: Si se conoce la clave primaria del objeto que se quiere buscar se debe utilizar la función read del módulo mnesia, que devuelve una lista con los registros almacenados cuya clave coincida con la clave especificada. Las funciones implementadas de esta forma son: get active user: Recibe como argumento el identificador de un Set Top Box, obtiene el registro que define dicho Set Top Box y después busca el registro que define el usuario cuya clave está referenciada en el campo user del Set Top Box obtenido. Aborta con la razón user not found si el Set Top Box no tiene un usuario asociado. get password: Recibe como argumento el identificador de un Set Top Box, lo busca y devuelve el campo passwd del mismo. get id from cookie: Recibe la cadena que identifica a una cookie, busca el registro que la representa y devuelve el campo id del mismo. Si se quieren buscar los registros de una tabla que cumplan un determinado patrón se usará la función match del módulo Mnesia que devuelve una lista con los registros que cumplen ese patrón. Este tipo de búsqueda lo realizan las funciones:

180 162 Capítulo 6. Implementación de VXMLS get languages: Devuelve todos los registros almacenados en la tabla language. get genres: Recibe como argumento un identificador de idioma y devuelve todos los registros que definen los géneros en ese idioma (los registros genre cuyo campo language id coincide con el argumento de la función). Si se necesitan los registros de una tabla que cumplan una determinada condición se puede utilizar la función select del módulo Mnesia. Esta función no fue necesaria para implementar ninguna de las búsquedas utilizadas por VXMLS. Para búsquedas más complejas se usarán consultas Mnemosyne (ver la sección 6.1.3), por ejemplo, para realizar uniones entre tablas. Las funciones implementadas con este método son las siguientes: get shown movies: Recibe como argumentos un identificador de idioma, un registro de un determinado usuario y un identificador de género. Debe devolver una lista de registros de tipo translated movie con información traducida al idioma correcto sobre las películas del género especificado que no han sido vistas por el usuario. Para ello debe ejecutar una unión entre las tablas movie, movie info y shown movies y seleccionar de entre estas que se ajusten al idioma y género especificados. La consulta ejecutada es la siguiente: Q = query [{Movie, MovieInfo} Movie <- table(movie), MovieInfo <- table(movie_info), ShownMovie <- table(shown_movie), Movie.genre_id = GenreId, MovieInfo.id = {Movie.id, LanguageId}, ShownMovie.id = User#user.id, ShownMovie.movie_id = Movie.id] end Las tuplas obtenidas serán procesadas para transformarlas en registros translated movie. get not shown movies: Recibe los mismos argumentos que la anterior más uno nuevo que indica si se deben seleccionar las novedades o el resto de películas. En este caso de deben devolver las películas que no están referenciadas en shown movies para el usuario especificado. Como la función anterior, devuelve una lista de registros translated movie.

181 Capa Modelo 163 get translated movie: Recibe como argumentos el identificador de una película y un identificador de idioma y devuelve la información en un registro translated movie con información de la película traducida al idioma especificado, para ello necesita hacer una unión entre las tablas movie y movie info. Q = query [{Movie, MovieInfo} Movie <- table(movie), MovieInfo <- table(movie_info), Movie.id = MovieId, MovieInfo.id = {MovieId, LanguageId}] end Funciones de edición de datos Para editar un campo de un registro almacenado en una tabla de Mnesia se debe ejecutar una transacción que siga estos pasos: 1. Obtener el registro con los valores viejos, normalmente utilizando la función wread del módulo mnesia, que obtiene un registro dada su clave y hacer que la transacción ejecute un bloqueo de escritura. 2. Crear una variable copiando los datos del registro anteriormente obtenido, excepto los datos que deben ser modificados. 3. Escribir este nuevo registro en la base de datos utilizando la función write del módulo mnesia. Las funciones que realizan este tipo de operación son: set active user: Modifica el usuario activo para un determinado Set Top Box. set cookie: Modifica el campo cookie de un Set Top Box para que señale a una nueva cookie, que también es almacenada en la base de datos por esta función. remove cookie: Modifica el campo cookie de un Set Top Box para indicar que no está asociado a ninguna cookie. También borra de la base de datos la cookie anteriormente referenciada por el Set Top Box.

182 164 Capítulo 6. Implementación de VXMLS Funciones de inserción de datos La inserción de datos se hace utilizando la función write del módulo mnesia dentro de una transacción. En caso de que se intente insertar un registro con una clave que ya esté presente en la base de datos, el nuevo registro suplantará al antiguo. Las funciones que insertan datos son todas aquellas que empiezan por new. La mayoría solamente son utilizadas durante la inicialización de la base de datos, los únicos datos que se insertarán durante la ejecución normal de VXMLS son los registros shown movie correspondientes a las películas que vayan viendo los usuarios y los valores de las cookies utilizadas para identificar las diferentes sesiones Funciones de acceso a los campos de un objeto valor Las siguientes funciones simplemente acceden al campo correspondiente del registro que se les pasa como argumento y devuelven su valor: get user name: Devuelve el nombre de un usuario. get language id: Devuelve el identificador ISO de un idioma. get language name: Devuelve el nombre de un idioma. get genre name: Devuelve el nombre de un género. get genre id: Devuelve el identificador de un género. get translated movie id: Devuelve el identificador de una película traducida. get translated movie title: Devuelve el título de una película traducida. get translated movie file: Devuelve el fichero en el que se encuentra el vídeo de una película traducida. get translated movie synopsys: Devuelve el resumen de una película traducida.

183 Capa Vista Capa Vista La vista de la aplicación se implementa en un único módulo vxmls xml, que exporta las funciones menu2xml, error report y ok message. Estas funciones permiten obtener los documentos XML que serán devueltos en las respuestas de VXMLS a las peticiones de los Set Top Boxes clientes. Durante la generación de un documento XML es necesario realizar varias concatenaciones de cadenas de texto (en Erlang una cadena de texto se representa como una lista de caracteres). La concatenación de listas es una operación costosa, ya que requiere que las dos listas involucradas sean recorridas completamente. Para evitar este problema, las cadenas se almacenarán en listas arbitrariamente profundas y se aplanarán al final de todo. De esta forma la función costosa, en este caso aplanar, sólo se ejecutará una vez. Por ejemplo, para concatenar la "hola ", con "mundo" se almacenarán en la lista ["hola ", "mundo"]. Una vez terminada la generación de las cadenas se obtendrá un lista profunda como, por ejemplo ["ejemplo:", ["hola ", "mundo"], [[[["."]]]]] la función flatten del módulo lists aplicada a esta lista devolverá la cadena esperada: "ejemplo:hola mundo.". Para la generación de los documentos XML, se definen las siguientes funciones internas al módulo: render empty tag: Recibe como argumentos el nombre de una etiqueta y, opcionalmente, una lista con pares argumento valor y devuelve una lista que representa a dicha etiqueta, con los argumentos especificados en caso de que los haya. También recibe como argumento una cadena que será añadida al principio de la lista devuelta. Esto es útil para indentar el resultado de forma que sea más legible. > flatten(render_empty_tag("", "etiqueta", [{"atributo", "valor"}])). > "<etiqueta atributo=\"valor\"/>\n" > > flatten(render_empty_tag("", "etiqueta")). > "<etiqueta/>\n" render tag: Es similar a la anterior, pero también recibe un argumento a mayores con el contenido de la etiqueta.

184 166 Capítulo 6. Implementación de VXMLS > flatten(render_tag("", "etiqueta", [{"atributo", "valor"}], "Contenido")). > "<etiqueta atributo=\"valor\">contenido</etiqueta>\n" > > flatten(render_tag("", "etiqueta", "Contenido")). > "<etiqueta>contenido</etiqueta>\n" Utilizando estas funciones, un registro menu se transforma en una representación XML utilizando la función render tag para una etiqueta menu cuyo contenido es otro conjunto de etiquetas que describen el menú. Para ejecutar esta función de forma sencilla se permite al módulo vxmls xml acceder a la representación interna de menú. render_menu(menu) -> render_tag("", "menu", ["\n", render_version(menu#menu.major_version, Menu#menu.minor_version), render_header(menu#menu.header), render_timer(menu#menu.timer), render_init_actions(menu#menu.init_actions), render_options(menu#menu.options)]). El resto de funciones render *** se implementan de forma similar. La función xml2menu obtendrá la representación del menú en XML utilizando la función anterior y le añadirá la cabecera XML para devolver el documento completo. Las funciones error report y ok message se pueden implementar utilizando las funciones render tag y render emtpy tag directamente. Por ejemplo, la función error report es como sigue: error_report(reason) -> [header("vxmls",?vxmls_dtd), %% cabecera XML render_tag("", "vxmls", ["\n", render_tag(" ", "error", Reason)])].

185 Capa Controlador Capa Controlador Generación de la respuesta HTTP Para la generación de los documentos HTTP a devolver se implementa la función http document que recibe como argumentos el contenido del documento y una lista con campos de la cabecera y sus correspondientes valores. Esta función aplanará la lista generada antes de devolverla, por lo que el contenido puede estar representado por una lista arbitrariamente profunda (ver la sección 6.3). También añadirá automáticamente el campo Content-length de acuerdo con el la longitud del contenido Traducción de mensajes En el módulo vxmls lang se implementa un servidor genérico (comportamiento gen server), que almacenará en su estado tablas con pares clave-valor en las que almacenar los mensajes a mostrar en la interfaz. Cada tabla guardará mensajes para un determinado idioma. Para almacenar esta información se utilizan las funciones del módulo ets del entorno Erlang/OTP. Este módulo permite crear tablas similares a las utilizadas en una base de datos, pero de carácter no persistente. Las tablas de los diferentes idiomas se cargan bajo demanda en el momento en el que se solicita un mensaje de un determinado idioma que no fuera sido cargado anteriormente. Los mensajes para cada idioma se describen en un fichero de texto de nombre vxmls lang.xx siendo xx el identificador ISO de idioma. Este fichero debe contener tuplas separadas por puntos de la forma {Clave, Cadena}. Estos valores se almacenarán en una tabla ets de nombre xx vxmls lang indexadas por Clave. Por ejemplo: suponiendo que el fichero vxmls lang.es contiene una línea {main_menu_header, "Menú Principal"}. una solicitud del mensaje a mostrar para main menu header en español devolverá la cadena Menú Principal.

186 168 Capítulo 6. Implementación de VXMLS Para ocultar la existencia del proceso servidor al resto de la aplicación, se exporta la función get message, a la que se le pasan el identificador del mensaje y el identificador ISO del idioma en el que se necesita el mensaje, obtiene dicho mensaje del servidor y lo devuelve Fachada En el módulo vxmls se definen las funciones que serán llamadas por Inets. Estas funciones deberán capturar los errores en un bloque catch para evitar la muerte del proceso utilizado por Inets para evaluar la función (ver la sección 6.1.7). De esta forma, se puede generar un mensaje de error explicativo utilizando la función error report del módulo vxmls xml. El módulo error manager exporta la función format error a la que se le pasa la razón del error y devuelve una cadena de texto informando de las causas del mismo Creación y destrucción de sesiones Las funciones login y logout del módulo vxmls utilizan las funciones con el mismo nombre del módulo vxmls login para crear y destruir respectivamente las sesiones de los clientes. login obtendrá los valores de los argumentos client y passwd pasados en la petición HTTP y comprobará que son válidos usando la función validate client del módulo vxmls lib. Esta función encriptará la clave en claro pasada en el argumento passwd y comprobará que la cadena coincide con la cadena encriptada almacenada en la base de datos (que obtiene utilizando las funciones exportadas por el modelo). En caso de que sea así se considera que el cliente está autorizado y se crea una sesión generando una cookie para el usuario y almacenándola en la base de datos. Después de esto genera una respuesta de confirmación con la función ok message del módulo vxmls xml y devuelve el documento HTTP correspondiente con los campos necesarios para indicarle al cliente que establezca la cookie. Para los usuarios registrados (es decir, para los que se ha creado una sesión), es posible acceder a sus datos utilizando la función validate cookie del módulo vxmls lib, que recibe como argumento la variable Env pasada por Inets (ver la sección 6.1.2), obtiene la cookie de la misma y utiliza las funciones del modelo para obtener el usuario asociado al Set Top Box para el que se creó la cookie. En caso de que la cookie no sea válida, esta función provoca el error not logged in o cookie not valid.

187 Capa Controlador 169 La función logout comprueba la sesión con validate cookie y elimina la cookie del modelo. Después de esto genera un mensaje de confirmación como en el caso anterior y devuelve un documento HTTP con los campos necesarios para indicarle al cliente que elimine la cookie. En caso de que se detecte algún error, ambas funciones devuelven un mensaje de error. case catch... % otros casos... { EXIT, Reason} -> http_document(error_report(format_error(reason)) end Propiedades de personalización La función set property del módulo vxmls delega su trabajo en la función con el mismo nombre del módulo vxmls properties. Esta función obtendrá el cliente asociado a la sesión utilizando la función validate cookie, el nombre y valor de la propiedad de los argumentos pasados en la petición HTTP y utilizará la función set property del modelo para realizar los cambios oportunos en el mismo. Después de esto devuelve un documento HTTP con un mensaje de confirmación. En caso de error devuelve un documento HTTP con un mensaje de error. Las propiedades que pueden ser definidas están determinadas por el modelo, en caso de que sea necesario añadir nuevas propiedades de personalización este módulo no necesita ser modificado, solamente se deberá ampliar la función set property del módulo vxmls db (ver la sección ) Generación de menús La función get menu del módulo vxmls delega en la función con el mismo nombre exportada por el módulo vxmls menu dispatcher. Este módulo se encargará de generar los documentos que representen el menú que se debe mostrar para cada petición, dependiendo del estado del modelo. Para añadir flexibilidad a la definición de la interfaz, el módulo vxmls menu dispatcher no generará los menús solicitados directamente, sino que obtendrá el documento XML de otros módulos que pueden ser cargados dinámicamente. De esta forma se puede variar la definición general de la interfaz sin modificar

188 170 Capítulo 6. Implementación de VXMLS el código existente, incluso sin tener que detener la aplicación. Los pasos que se siguen para obtener la definición XML de un determinado menú son los siguientes: 1. Comprobar que la sesión es válida y obtener el identificador del Set Top Box cliente con la función validate sesion del módulo vxmls lib. 2. Obtener los datos del usuario activo del Set Top Box utilizando las funciones del modelo. 3. Obtener el valor de argumento menu en la URL, y una lista con el resto de pares argumento-valor. 4. Generar el documento XML llamando a la función xml document del módulo asociado al menú solicitado. El nombre del módulo que genera el menú será vxmls nombre, donde nombre es el nombre del menú obtenido en el paso 3. De esta forma, el módulo vxmls menu dispatcher no depende de los nombres de los menús definidos ni de los argumentos que estos reciben. En caso de que se desee añadir un nuevo menú, por ejemplo nuevo menu, se deberá escribir un nuevo módulo vxmls nuevo menu que exporte una función xml document de acuerdo con la siguiente especificación: Recibe cuatro argumentos: ClientId, User, LanguageId y Arguments. ClientId: Identificador del Set Top Box cliente asociado a la sesión. User: Describe el usuario activo en el Set Top Box, los valores de sus atributos se pueden obtener con las funciones del modelo (ver la sección ). En caso del que el Set Top Box no tenga asociado un usuario activo este valor será false. LanguageId: Identificador ISO del idioma en el que se debe mostrar el menú. El módulo vxmls menu dispatcher pasa el idioma por defecto en este campo en caso de que el Set Top Box no tenga un usuario asociado. Arguments: Lista de pares nombre-valor con los argumentos con los que se solicita el menú. Deberá devolver una lista arbitrariamente profunda que represente el documento XML que define el menú solicitado. En caso de que se produzca algún error, la función debe causar la finalización del proceso que la ejecuta.

189 Capa Controlador Composición de objetos Menu El módulo vxmls menu exporta una serie de funciones para crear objetos Menu sin necesidad de conocer la estructura interna de este tipo. compose: Recibe como argumento una lista de componentes y devuelve el objeto Menu correspondiente. Los componentes se puede generar con el resto de funciones exportadas por este módulo. timer: Genera un objeto Timer, recibe como argumentos el tiempo la lista de acciones a ejecutar en caso de que éste expire. action: Genera un objeto Action. Recibe como argumentos el tipo de la acción y los datos que sean necesarios para definirla. option: Genera una opción. Recibe como argumentos el texto a mostrar para la opción y la lista de acciones a ejecutar en caso de que la opción sea seleccionada. default change option actions: Devuelve una lista con las acciones para cambiar la opción seleccionada. default bind key actions: Devuelve una lista con las acciones que vinculan las teclas arriba, abajo, SEL y STOP con las acciones definidas por defecto para la navegación por los menús. default cancel option: Devuelve una opción Cancelar genérica, que en caso de ser seleccionada provoca la vuelta al menú anterior. default next menu option: Devuelve una opción genérica para saltar a otro menú. no show next menu option: Similar a la anterior, pero oculta el menú al que se salta. Por ejemplo, para generar el un menú que muestra las opciones para acceder la selección de idioma o a la selección de usuario se utiliza el siguiente código (se han eliminado las referencias a los módulos): xml_document(_client, _User, LanguageId, []) -> Header = get_message(languageid, settings_header), Menu = compose([{header, Header}, {init_actions, default_bind_key_actions()},

190 172 Capítulo 6. Implementación de VXMLS menu2xml(menu). {options, settings_options(languageid)}]), settings_options(languageid) -> ChooseUser = get_message(languageid, settings_choose_user), ChooseLanguage = get_message(languageid, settings_choose_language), [no_show_next_menu_option(chooseuser, "choose_user_menu"), no_show_next_menu_option(chooselanguage, "language_menu"), default_cancel_option(languageid)] Menús definidos La interfaz definida se compone de los siguientes menús: main menu: Menú mostrado como raíz de la interfaz. Sus opciones permiten el acceso al menú settings menu y a movies menu. settings menu: Contiene opciones que permiten acceder a los menús choose user menu y language menu. choose user menu: Permite elegir entre los distintos usuarios asociados al Set Top Box. language menu: Permite elegir el idioma en el que se desea que se muestre la interfaz. movies menu: Sus opciones permiten acceder al menú genre menu con los argumentos necesarios, dependiendo de si se desea obtener una lista con las novedades, una lista con películas antiguas o una lista con las películas vistas. genre menu: Muestra opciones para acceder al menú movie list menu con los argumentos necesarios para mostrar las películas, nuevas, antiguas o vistas del género seleccionado. movie list menu: Muestra opciones para acceder al menú movie menu para una determinada película. movie menu: Sus opciones permiten iniciar la reproducción del vídeo al tiempo que se accede al menú video playing menu (que inicialmente estará oculto), o acceder al menú synopsys menu.

191 Capa Controlador 173 video playing menu: Muestra opciones para avanzar, retroceder, continuar o terminar la reproducción de vídeo. synopsys menu: No tiene opciones, muestra un resumen de la película en pantalla. video end menu: Aparece cuando un vídeo finaliza, sus opciones permiten iniciar de nuevo la reproducción del vídeo o regresar al menú movie menu Ejemplos de vxmls get menu main menu El menú main menu está definido en el módulo vxmls main menu. En un principio deberá mostrar dos opciones, una para acceder al menú de personalización y otra para acceder al los menús de selección de películas, pero en caso de que el Set Top Box no tenga asociado ningún usuario (es la primera vez que accede a VXMLS) se debe mostrar el menú de selección de usuario directamente. Este menú no recibe argumentos, a no ser que se solicite como resultado de una acción ReloadMenu, en cuyo caso recibe el argumento reloaded con valor true (ver la sección ). En primer lugar, la función xml document comprueba que el argumento User no es false, de ser así, devuelve el resultado obtenido de la función xml document del módulo vxmls choose user menu que define el menú de selección de usuario. Una vez comprobado que el Set Top Box tiene asociado un usuario obtiene la cabecera a mostrar para el menú solicitando el mensaje main menu header al servidor vxmls lang (ver la sección 6.4.2) y genera la lista de acciones de inicialización y la lista de opciones (para lo que también deberá solicitar a vxmls lang las cadenas a mostrar para cada una) y obtiene un objeto Menu utilizando la función compose menu del módulo vxmls menu, explicado en la sección El objeto Menu obtenido se transforma en un documento XML utilizando la función menu2xml del módulo vxmls xml y se devuelve como resultado movie list menu El módulo vxmls movie list menu se encargará de generar los menús que permiten al usuario seleccionar una película. Este menú recibe los parámetros filter, que puede tener los valores old, premiere o shown, y genre que tiene como valor el identificador de un género. La función xml document de este módulo

192 174 Capítulo 6. Implementación de VXMLS devolverá la descripción de un menú que tendrá como opciones las películas del género especificado y que cumplan las condiciones impuestas por el argumento filter. old: Películas no vistas y que no sean novedad. premiere: Películas no vistas clasificadas como novedad. shown: Películas ya vistas. La generación de este menú pasa por las siguientes fases: 1. Obtener el valor del género y del filtro de entre los argumentos recibidos. 2. Obtener el texto a mostrar en la cabecera del menú, utilizando el servidor vxmls lang (ver la sección 6.4.2). 3. Obtener la lista de películas para el género y filtro especificado utilizando las funciones necesarias del modelo. 4. Generar una opción para cada película con ayuda de las funciones del módulo vxmls menu (ver la sección 6.4.7). 5. Con todo esto, crear el objeto Menu utilizando la función compose menu del módulo vxmls menu. 6. Generar el documento XML con la función menu2xml del módulo vxmls xml synopsys menu Este menú es ligeramente especial ya que no define ninguna opción y no se llegará a mostrar, se mantiene siempre oculto. El objetivo de este menú es mostrar en pantalla un resumen sobre una determinada película. Para ello, sus acciones de inicialización no enlazarán las teclas por defecto, como la mayoría del resto de menús, sino que mostrarán el resumen en pantalla (acción ShowText) y enlazarán las teclas SEL y STOP con las acciones para volver al menú anterior, ocultando el resumen. Para generar este menú, el módulo vxmls synopsys menu exporta una función xml document que sigue los siguientes pasos: 1. Obtener el identificador de la película del argumento movie.

193 Extensibilidad Obtener el resumen sobre la película, traducida al idioma correspondiente, utilizando las funciones del modelo. 3. Crear el objeto menú con las funciones del módulo vxmls menu. 4. Devolver el documento XML obtenido de transformar el objeto obtenido en el paso anterior utilizando la función menu2xml del módulo vxmls xml Extensibilidad Como se explicó en apartados anteriores, DFBCIn se ha diseñado e implementado de forma que fuera sencillo incorporar nuevas funcionalidades extendiendo la interfaz Action. VXMLS es el encargado de dirigir el comportamiento de DFBCIn, por lo que en el momento en que DFBCIn sea capaz de realizar nuevas tareas se debe modificar VXMLS para que pueda comunicarle a DFBCIn que realice dichas tareas en algún instante determinado. Para añadir el soporte para una nueva acción en VXMLS es necesario agregar código en los módulos vmxls menu y vxmls xml. En vxmls menu es necesario añadir un nuevo caso a action para que pueda generar un objeto Action para la nueva acción. Así mismo, puede ser necesario añadir un nuevo registro en la cabecera vxmls menu.hrl para almacenar la información sobre la acción. En vxmls xml se debe añadir un nuevo caso en la función render action para que pueda transformar la nueva acción en un bloque XML. Normalmente, dadas las características de Erlang, estas modificaciones sólo suponen añadir una nueva clausula a las funciones ya existentes. Por ejemplo, cuando se añadió la acción LoadMp3 sólo fue necesario hacer las siguientes modificaciones: En la cabecera vxmls menu.hrl, se añade un nuevo registro load mp3 con el campo path para almacenar la información sobre el fichero o URL que se debe cargar: -record(action, {type, data = false }). % Tipo de acción % Información sobre la misma

194 176 Capítulo 6. Implementación de VXMLS %%% Registros para almacentar información en el campo %%% data de action -record(change_option, {value, mode }). % An integer % (?RELATIVE?ABSOLUTE) % Continúa con la definición de otros registros % para las diferentes acciones %... %%% Nuevo registro para la acción recién a~nadida -record(load_mp3, {path % The file path (or URI) }). En el fichero vxmls menu.erl se debe añadir un nuevo caso a la función action para que pueda crear acciones de este tipo: action(show_text, Lines) when list(lines) -> Data = #show_text{lines = Lines}, #action{type=show_text, data = Data}; % Constructores para otras acciones %... %%% Nuevo constructor para una acción LoadMp3 action(load_mp3, Path) when list(path) -> Data = #load_mp3{path = Path}, #action{type = load_mp3, data = Data}. En el fichero vxmls xml.erl se añade un nuevo caso para la nueva acción en la función render action para que pueda generar el código XML para esta nueva acción: render_action(indent, unload_video, _Data) -> render_empty_tag(indent, "unloadvideo"); % Otras funciones para renderizar las distintas acciones

195 Extensibilidad 177 %... %%% Nuevo caso para renderizar la función recién a~nadida render_action(indent, load_mp3, Data) -> render_empty_tag(indent, "loadmp3", [{"path", Data#load_mp3.path}]); %... Como se vio en este mismo capítulo en la sección 6.4.6, la implementación de VXMLS posibilita modificar la interfaz definida sin afectar a los módulos existentes, salvo aquellos módulos que son los encargados de devolver los documentos XML correspondientes a cada menú particular. Por lo tanto, redefinir la interfaz mostrada para adaptarla a las posibilidades que ofrecen las nuevas acciones sólo afecta al código de los módulos que definen cada menú.

196

197 Capítulo 7 Validación Índice General 7.1. Despliegue del sistema Tamaño del software para el Set Top Box DFBCIn Problemas de rendimiento Problemas con avifile VXMLS Comportamiento general Problemas con Inets Streaming Despliegue del sistema El sistema utilizado para la validación de las pruebas se compone de los siguientes subsistemas: DFBCIn se ejecutará en el Set Top Box explicado en la sección VXMLS se ejecutará en un PC conectado por red al Set Top Box. VoDKA correrá sobre un cluster de máquinas. 179

198 180 Capítulo 7. Validación PC ejecutando VXMLS Red de interconexion Cluster servidor de video DFBCIn funcionando en el Set Top Box Figura 7.1: Despliegue del sistema final 7.2. Tamaño del software para el Set Top Box En el Set Top Box utilizado para las pruebas se instaló un disco duro para facilitar el desarrollo, pero el sistema final debería caber en una memoria flash. El tamaño de los diferentes componentes de software que se deben instalar es: Aplicación DFBCIn: Al ser una aplicación escrita C en y enlazada dinámicamente con las bibliotecas utilizadas, el espacio ocupado se reduce a 548 kilobytes, entre los que se cuentan las imágenes y fuentes utilizadas para dibujar la interfaz y la biblioteca dinámica utilizada para implementar el módulo gráfico. DirectFB : A pesar de estar enlazada estáticamente, DirectFB es una librería muy ligera en cuanto a espacio ocupado, sólo ocupa 4,4 megabytes. Avifile: La versión utilizada de avifile necesita una instalación de 13 megabytes. Expat: La biblioteca expat solamente necesita la instalación de 804 kilobytes. Instalación de Linux: Los más de 40 mega bytes restantes (asumiendo una memoria Flash de 64 megabytes) son más que suficientes para una instalación de Linux sin X Windows. El sistema completo puede ser almacenado en una memoria Flash de 64 mega bytes. Nótese que en caso de que se hubiera utilizado el sistema X Windows esto

199 DFBCIn 181 sería imposible, ya que una instalación típica de dicho sistema ocupa más de esos 64 mega bytes DFBCIn La aplicación DFBCIn se ejecutará sobre un Set Top Box conectado a un televisor, utilizando un mando a distancia como sistema de entrada. Figura 7.2: DFBCIn funcionando en el Set Top Box Se observó el correcto funcionamiento del mando a distancia y de la salida de televisión del Set Top Box Problemas de rendimiento La tarjeta gráfica incorporada por el Set Top Box utilizado, una SiS 650, no está soportada por la versión de DirectFB utilizada, esto quiere decir que todas las operaciones serán realizadas sin ayuda de la aceleración hardware proporcionada por la tarjeta. Debido a esto, la reproducción de vídeo que se consiguió en un principio era demasiado pobre, ya que la CPU no era suficientemente rápida para decodificar y dibujar todos los frames en tiempo real. Para aligerar la carga durante, la primera medida tomada fue la de disminuir la resolución de salida, que originalmente era 800x600, a 640x480, con una profundidad de color de 16 bits. Con esta medida se consiguió una pequeña mejora, pero el vídeo seguía acusando saltos evidentes. Lo siguiente que se intentó fue adaptar el tamaño del

200 182 Capítulo 7. Validación vídeo para evitar tener que realizar escalados a la hora de copiar los frames en la superficie primaria. Se comprobó que con un vídeo codificado con un ancho de 640 pixels, de forma que la copia de los frames a la superficie primaria simplemente consiste en una copia byte a byte, los resultados obtenidos fueron casi aceptables. La solución definitiva fue codificar los vídeos con un ancho de 320 pixels. La copia de los frames a la superficie primaria supone una operación de escalado, pero escalar al doble de tamaño es relativamente sencillo (sólo se deben duplicar los pixels), y el ahorro computacional que supone trabajar con imágenes que ocupan la cuarta parte que en el caso anterior es suficiente para que el flujo de frames sea suave. La perdida de resolución se hace evidente en un monitor, pero las pruebas en la televisión resultaron bastante aceptables. Aún así, operaciones tales como reproducir vídeo con un menú dibujado por encima ralentizan el sistema de forma que el vídeo vuelve a saltar de forma desagradable. Para evitar esto de diseñó la interfaz definida por VXMLS de forma que siempre se detenga el vídeo antes de dibujar un menú por encima. El menú se dibujará sobre un frame estático, por lo que no habrá problemas de ralentización Problemas con avifile La implementación de IDirectFBVideoProvider para ficheros AVI distribuida con DirectFB utiliza la versión 0.6 de la biblioteca avifile. Durante las pruebas se detectaron varios problemas: 1. Al final de la reproducción, el vídeo vuelve a empezar, esto imposibilita por completo la detección del final del vídeo tal y como se explicó en la sección El problema se encontró en las fuentes de avifile, que explícitamente volvían al principio del vídeo cuando se alcanzaba el final (presumiblemente debido a un cambio hecho para alguna prueba por los programadores de DirectFB). 2. Utilizando el proveedor de avifile, DFBCIn se colgaba al ejecutar una acción VideoStop durante la reproducción de vídeo. El problema se encontró en un interbloqueo entre Interface (ver la sección ) y la reproducción de vídeo controlada por avifile. Cuando Interface llama a videostop para detener la reproducción debe esperar a que esta función termine, manteniendo su estado bloqueado, avifile intenta terminar de decodificar un frame antes de detener la reproducción, cuando tiene el frame disponible ejecuta la función videocallback que fue instalada en videoload y después debería detener la reproducción. El problema surge porque videocallback debe ejecutar la función notifynewframe para

201 VXMLS 183 avisar a Interface de que hay un nuevo frame disponible, y esta función necesita acceder al estado de Interface para modificar sus banderas, por lo que debe esperar a que Interface libere el semáforo que esta tiene bloqueado mientras trata de terminar la ejecución de videostop. 3. Si se produce un fallo durante la reproducción de vídeo (no debería producirse ningún fallo, pero recuérdese que para terminar la aplicación durante las pruebas se provoca un fallo de forma intencionada), DFBCIn termina de forma incontrolada, a veces provocando fallos de segmento y otras quedando totalmente bloqueada. Este fallo se debe a que la implementación del proveedor de vídeo para avifile no es completa y no sincroniza la destrucción del reproductor de vídeo con la liberación de las superficies utilizadas. Se puede dar el caso de que se intente escribir un nuevo frame en una superficie que ya no tiene memoria reservada. 4. La versión 0.6 se avifile utiliza los codecs de Windows en vez de utilizar una biblioteca nativa de Linux, por lo que se produce una sobrecarga debida a las emulaciones necesarias. 5. Las funciones GetPos y SeekTo no siempre funcionan correctamente. El problema 1 se solucionó eliminando esa característica en las fuentes de avifile. El problema 2 se solucionó desplazando la llamada a la función de Interface interfacenotifynewframe a un nuevo hilo de ejecución. Durante la inicialización de Video (ver la sección ) se crea un nuevo hilo interfacenotifier que será despertado por la función instalada durante videoload como callback en el proveedor. Una vez despertado este hilo llamará a interfacenotifynewframe (deberá esperar en algunos casos a que Interface libere su estado, pero ahora no bloquea la ejecución) y volverá a dormirse (ver la sección ). Para solucionar el problema 2 se reescribió el código del proveedor de vídeo proporcionado por DirectFB para adaptarlo a la versión de avifile, que ya permite la utilización de otros codecs, como los de la biblioteca de Linux ffmpeg. En el apéndice C se puede ver la interfaz a implementar para un proveedor de vídeo. El nuevo proveedor de vídeo implementado ya no tiene el problema 1. Los problemas 3 y 5 están todavía sin solucionar. El problema de la liberación de memoria se debe solucionar mejorando la implementación del proveedor de vídeo y el segundo problema parece que es debido a un fallo en avifile.

202 184 Capítulo 7. Validación 7.4. VXMLS Comportamiento general VXMLS se ejecuta sobre un PC convencional, para comprobar que el correcto funcionamiento durante la ejecución de las pruebas se utilizaron diversas herramientas suministradas con la plataforma Erlang/OTP, como la aplicación tv que permite ver los contenidos de las tablas de Mnesia y de las tablas ets y la aplicación pman que permite monitorizar los procesos en ejecución dentro de un nodo Erlang. No se detectaron problemas en el funcionamiento de VXMLS, la interfaz definida funciona correctamente y los datos almacenados en la base de datos influyen en la misma como es esperado Problemas con Inets Durante las pruebas de sistema se comprobó que Inets no cerraba la conexión inmediatamente a pesar de enviar el campo Connection: close [35] en la cabecera, sino que tardaba una pequeña fracción de tiempo desde que terminaba de enviar la respuesta hasta que cerraba la conexión. Esto provocaba que la aplicación DFBCIn quedara bloqueada a la espera de que se cerrara la conexión, lo que derivaba en una molesta latencia entre el momento en el que el usuario pulsaba una tecla a la que estaba asociada alguna acción que necesitara realizar una petición a VXMLS para completar su ejecución y el momento en el que los resultados de la ejecución de dicha acción se hacían visibles. Para solucionar este problema, se implementó VXMLS de forma que añadiera el campo Content-Length y se hizo que httpget diera prioridad a la información de dicho campo sobre el hecho de saber que la conexión va a ser cerrada (ver la sección ) Streaming Tras las pruebas ejecutadas utilizando ficheros locales para comprobar el correcto funcionamiento de DFBCIn en cuanto a reproducción de vídeo, se realizaron las pruebas sobre medios servidos por VoDKA. Para ello se utilizó el sistema de ficheros virtual desarrollado en [37], que permite el acceso a medios distribuidos por streaming sin modificar la implementación del reproductor de vídeo, introduciendo una serie de capas que ocultan el

203 Streaming 185 acceso al medio remoto como si de un fichero local se tratara. En la figura 7.3 se muestra un diagrama con las capas introducidas por este proxy. DFBCIn Proveedor de Video Proxy Sistema Virtual de Ficheros Sistema de Buffers Protocolo de Streaming Servidor de Video Red Figura 7.3: Capas de acceso al servicio de streaming La reproducción de vídeo utilizando esta técnica supone una carga computacional añadida para el Set Top Box lo que en ocasiones puede disminuir la calidad del vídeo reproducido, dependiendo de la capacidad del Set Top Box.

204 Figura 7.4: Cluster servidor de vídeo utilizado

Los mayores cambios se dieron en las décadas de los setenta, atribuidos principalmente a dos causas:

Los mayores cambios se dieron en las décadas de los setenta, atribuidos principalmente a dos causas: SISTEMAS DISTRIBUIDOS DE REDES 1. SISTEMAS DISTRIBUIDOS Introducción y generalidades La computación desde sus inicios ha sufrido muchos cambios, desde los grandes equipos que permitían realizar tareas

Más detalles

Capítulo 5. Cliente-Servidor.

Capítulo 5. Cliente-Servidor. Capítulo 5. Cliente-Servidor. 5.1 Introducción En este capítulo hablaremos acerca de la arquitectura Cliente-Servidor, ya que para nuestra aplicación utilizamos ésta arquitectura al convertir en un servidor

Más detalles

Tecnología IP para videovigilancia... Los últimos avances han hecho posible conectar cámaras directamente a una red de ordenadores basada en el

Tecnología IP para videovigilancia... Los últimos avances han hecho posible conectar cámaras directamente a una red de ordenadores basada en el para videovigilancia....... Los últimos avances han hecho posible conectar cámaras directamente a una red de ordenadores basada en el protocolo IP. La tecnología de las cámaras de red permite al usuario

Más detalles

Introducción a las redes de computadores

Introducción a las redes de computadores Introducción a las redes de computadores Contenido Descripción general 1 Beneficios de las redes 2 Papel de los equipos en una red 3 Tipos de redes 5 Sistemas operativos de red 7 Introducción a las redes

Más detalles

Informática 4º ESO Tema 1: Sistemas Informáticos. Sistemas Operativos (Parte 2)

Informática 4º ESO Tema 1: Sistemas Informáticos. Sistemas Operativos (Parte 2) 1. Qué es un sistema operativo?...2 2. Funciones de los sistemas operativos...2 3. Windows...2 3.1. La interfaz gráfica...2 3.2. La administración y los usuarios...3 3.3. El sistema de archivos...3 3.4.

Más detalles

Elementos requeridos para crearlos (ejemplo: el compilador)

Elementos requeridos para crearlos (ejemplo: el compilador) Generalidades A lo largo del ciclo de vida del proceso de software, los productos de software evolucionan. Desde la concepción del producto y la captura de requisitos inicial hasta la puesta en producción

Más detalles

FileMaker Pro 13. Uso de una Conexión a Escritorio remoto con FileMaker Pro 13

FileMaker Pro 13. Uso de una Conexión a Escritorio remoto con FileMaker Pro 13 FileMaker Pro 13 Uso de una Conexión a Escritorio remoto con FileMaker Pro 13 2007-2013 FileMaker, Inc. Reservados todos los derechos. FileMaker, Inc. 5201 Patrick Henry Drive Santa Clara, California 95054

Más detalles

Guía de uso del Cloud Datacenter de acens

Guía de uso del Cloud Datacenter de acens guíasdeuso Guía de uso del Cloud Datacenter de Calle San Rafael, 14 28108 Alcobendas (Madrid) 902 90 10 20 www..com Introducción Un Data Center o centro de datos físico es un espacio utilizado para alojar

Más detalles

Windows Server 2003. Windows Server 2003

Windows Server 2003. Windows Server 2003 Windows Server 2003 Windows Server 2003 Es un sistema operativo de la familia Windows de la marca Microsoft para servidores que salió al mercado en el año 2003. Está basada en tecnología NT y su versión

Más detalles

GLOSARIO. Arquitectura: Funcionamiento, estructura y diseño de una plataforma de desarrollo.

GLOSARIO. Arquitectura: Funcionamiento, estructura y diseño de una plataforma de desarrollo. GLOSARIO Actor: Un actor es un usuario del sistema. Esto incluye usuarios humanos y otros sistemas computacionales. Un actor usa un Caso de Uso para ejecutar una porción de trabajo de valor para el negocio.

Más detalles

FileMaker Pro 14. Uso de una Conexión a Escritorio remoto con FileMaker Pro 14

FileMaker Pro 14. Uso de una Conexión a Escritorio remoto con FileMaker Pro 14 FileMaker Pro 14 Uso de una Conexión a Escritorio remoto con FileMaker Pro 14 2007-2015 FileMaker, Inc. Reservados todos los derechos. FileMaker, Inc. 5201 Patrick Henry Drive Santa Clara, California 95054

Más detalles

Capítulo 4: Requerimientos.

Capítulo 4: Requerimientos. Capítulo 4: Requerimientos. Una vez que se ha analizado con detalle los nuevos paradigmas en la educación, nos podemos dar cuenta que para poder apoyar cambios como estos y para poder desarrollar nuevos

Más detalles

COLEGIO COMPUESTUDIO

COLEGIO COMPUESTUDIO COLEGIO COMPUESTUDIO ÁREA: TECNOLOGIA E INFORMATICA DOCENTE: WILLY VIVAS LLOREDA ESTUDIANTE: CLEI: III GUIA N 5 N SESIONES: NUCLEO TEMÁTICO: UNIDAD: 2 Sistema operativo (Windows) OBJETIVO: Comprender el

Más detalles

Maquinas virtuales Conceptos Básicos

Maquinas virtuales Conceptos Básicos Jimenez Zamudio Eduardo Aplicaciones de redes de computadoras 13 de septiembre de 2014 Maquinas virtuales Conceptos Básicos Concepto Básicamente, es un equipo dentro de un equipo, implementado en el software.

Más detalles

LINEAMIENTOS ESTÁNDARES APLICATIVOS DE VIRTUALIZACIÓN

LINEAMIENTOS ESTÁNDARES APLICATIVOS DE VIRTUALIZACIÓN LINEAMIENTOS ESTÁNDARES APLICATIVOS DE VIRTUALIZACIÓN Tabla de Contenidos LINEAMIENTOS ESTÁNDARES APLICATIVOS DE VIRTUALIZACIÓN... 1 Tabla de Contenidos... 1 General... 2 Uso de los Lineamientos Estándares...

Más detalles

Ayuda de Symantec pcanywhere Web Remote

Ayuda de Symantec pcanywhere Web Remote Ayuda de Symantec pcanywhere Web Remote Conexión desde un navegador web Este documento incluye los temas siguientes: Acerca de Symantec pcanywhere Web Remote Protección de la sesión de Web Remote Formas

Más detalles

Windows Server 2012: Infraestructura de Escritorio Virtual

Windows Server 2012: Infraestructura de Escritorio Virtual Windows Server 2012: Infraestructura de Escritorio Virtual Módulo 1: Application Virtualization Módulo del Manual Autores: James Hamilton-Adams, Content Master Publicado: 5 de Octubre 2012 La información

Más detalles

Windows Server 2012: Identidad y Acceso. Módulo 2: Descripción General de Windows Server 2012 Remote Desktop Services.

Windows Server 2012: Identidad y Acceso. Módulo 2: Descripción General de Windows Server 2012 Remote Desktop Services. Windows Server 2012: Identidad y Acceso Módulo 2: Descripción General de Windows Server 2012 Remote Desktop Services. Manual del Módulo Autor: Andrew J Warren, Content Master Publicado: Septiembre 10 de

Más detalles

UNIVERSIDAD TECNOLOGICA ECOTEC DIEGO BARRAGAN MATERIA: Sistemas Operativos 1 ENSAYO: Servidores BLADE

UNIVERSIDAD TECNOLOGICA ECOTEC DIEGO BARRAGAN MATERIA: Sistemas Operativos 1 ENSAYO: Servidores BLADE UNIVERSIDAD TECNOLOGICA ECOTEC DIEGO BARRAGAN MATERIA: Sistemas Operativos 1 ENSAYO: Servidores BLADE AÑO: 2010 Qué es un servidor Blade? Blade Server es una arquitectura que ha conseguido integrar en

Más detalles

COMO CONFIGURAR UNA MAQUINA VIRTUAL EN VIRTUALBOX PARA ELASTIX

COMO CONFIGURAR UNA MAQUINA VIRTUAL EN VIRTUALBOX PARA ELASTIX COMO CONFIGURAR UNA MAQUINA VIRTUAL EN VIRTUALBOX PARA ELASTIX En este manual se presenta el proceso de configuración de una Maquina Virtual en VirtualBox, que será utilizada para instalar un Servidor

Más detalles

Guía de selección de hardware Windows MultiPoint Server 2010

Guía de selección de hardware Windows MultiPoint Server 2010 Guía de selección de hardware Windows MultiPoint Server 2010 Versión de documento 1.0 Publicado en marzo del 2010 Información sobre los derechos de reproducción Este documento se proporciona como está.

Más detalles

Modulo I. Introducción a la Programación Web. 1.1 Servidor Web.

Modulo I. Introducción a la Programación Web. 1.1 Servidor Web. Modulo I. Introducción a la Programación Web. 1.1 Servidor Web. Antes de analizar lo que es un servidor Web y llevara a cabo su instalación, es muy importante identificar diferentes elementos involucrados

Más detalles

Soluciones innovadoras para optimizar su infraestructura TI. Virtualización con el sistema operativo i, PowerVM y Power Systems de IBM

Soluciones innovadoras para optimizar su infraestructura TI. Virtualización con el sistema operativo i, PowerVM y Power Systems de IBM Soluciones innovadoras para optimizar su infraestructura TI Virtualización con el sistema operativo i, PowerVM y Power Systems de IBM Características principales Tenga éxito en su negocio simplemente con

Más detalles

Propuesta de Portal de la Red de Laboratorios Virtuales y Remotos de CEA

Propuesta de Portal de la Red de Laboratorios Virtuales y Remotos de CEA Propuesta de Portal de la Red de Laboratorios Virtuales y Remotos de CEA Documento de trabajo elaborado para la Red Temática DocenWeb: Red Temática de Docencia en Control mediante Web (DPI2002-11505-E)

Más detalles

Visión General de GXportal. Última actualización: 2009

Visión General de GXportal. Última actualización: 2009 Última actualización: 2009 Copyright Artech Consultores S. R. L. 1988-2009. Todos los derechos reservados. Este documento no puede ser reproducido en cualquier medio sin el consentimiento explícito de

Más detalles

CAPÍTULO 1 Instrumentación Virtual

CAPÍTULO 1 Instrumentación Virtual CAPÍTULO 1 Instrumentación Virtual 1.1 Qué es Instrumentación Virtual? En las últimas décadas se han incrementado de manera considerable las aplicaciones que corren a través de redes debido al surgimiento

Más detalles

UNIVERSIDAD DE ORIENTE FACULTAD DE ICIENCIAS ECONOMICAS LAS REDES I. Licda. Consuelo Eleticia Sandoval

UNIVERSIDAD DE ORIENTE FACULTAD DE ICIENCIAS ECONOMICAS LAS REDES I. Licda. Consuelo Eleticia Sandoval UNIVERSIDAD DE ORIENTE FACULTAD DE ICIENCIAS ECONOMICAS LAS REDES I Licda. Consuelo Eleticia Sandoval OBJETIVO: ANALIZAR LAS VENTAJAS Y DESVENTAJAS DE LAS REDES DE COMPUTADORAS. Que es una red de computadoras?

Más detalles

Sistema Operativo Windows

Sistema Operativo Windows Sistema Operativo Windows Constantemente se hacen mejoras a los sistemas operativos por lo que existen diferentes versiones actualizadas de Windows. Las más usadas en la actualidad son: Windows XP, Windows

Más detalles

Operación Microsoft Windows

Operación Microsoft Windows Entornos de red Concepto de red En el nivel más elemental, una red consiste en dos equipos conectados entre sí mediante un cable de forma tal que puedan compartir datos. Todas las redes, no importa lo

Más detalles

Este documento se distribuye bajo los términos de la licencia Creative Commons by sa. http://creativecommons.org/licenses/by sa/2.

Este documento se distribuye bajo los términos de la licencia Creative Commons by sa. http://creativecommons.org/licenses/by sa/2. Análisis de aplicación: Visual Understanding Environment (VUE) Este documento ha sido elaborado por el Centro de excelencia de software libre de Castilla La Mancha (Ceslcam, http://ceslcam.com). Copyright

Más detalles

Lectura 2: El Sistema Operativo y sus Funciones

Lectura 2: El Sistema Operativo y sus Funciones MOMENTO I. BLOQUE 1. Opera las funciones básicas del sistema operativo y garantiza la seguridad de la información Objetos de aprendizaje: Sistema Operativo Lectura 2: El Sistema Operativo y sus Funciones

Más detalles

UNIVERSIDAD DE SALAMANCA

UNIVERSIDAD DE SALAMANCA UNIVERSIDAD DE SALAMANCA FACULTAD DE CIENCIAS INGENIERÍA TÉCNICA EN INFORMÁTICA DE SISTEMAS Resumen del trabajo práctico realizado para la superación de la asignatura Proyecto Fin de Carrera. TÍTULO SISTEMA

Más detalles

PROCEDIMIENTO ESPECÍFICO. Código G083-01 Edición 0

PROCEDIMIENTO ESPECÍFICO. Código G083-01 Edición 0 Índice 1. TABLA RESUMEN... 2 2. OBJETO... 2 3. ALCANCE... 2 4. RESPONSABILIDADES... 3 5. ENTRADAS... 3 6. SALIDAS... 3 7. PROCESOS RELACIONADOS... 3 8. DIAGRAMA DE FLUJO... 4 9. DESARROLLO... 5 9.1. DEFINICIÓN...

Más detalles

Instalar protocolo, cliente o servicio nuevo. Seleccionar ubicación de red. Práctica - Compartir y conectar una carpeta

Instalar protocolo, cliente o servicio nuevo. Seleccionar ubicación de red. Práctica - Compartir y conectar una carpeta Configuración de una red con Windows Aunque existen múltiples sistemas operativos, el más utilizado en todo el mundo sigue siendo Windows de Microsoft. Por este motivo, vamos a aprender los pasos para

Más detalles

Acronis License Server. Guía del usuario

Acronis License Server. Guía del usuario Acronis License Server Guía del usuario TABLA DE CONTENIDO 1. INTRODUCCIÓN... 3 1.1 Generalidades... 3 1.2 Política de licencias... 3 2. SISTEMAS OPERATIVOS COMPATIBLES... 4 3. INSTALACIÓN DE ACRONIS LICENSE

Más detalles

Antivirus PC (motor BitDefender) Manual de Usuario

Antivirus PC (motor BitDefender) Manual de Usuario Antivirus PC (motor BitDefender) Manual de Usuario Índice 1. Introducción... 3 2. Qué es Antivirus PC?... 3 a. Eficacia... 3 b. Actualizaciones... 4 3. Requisitos técnicos... 4 a. Conocimientos técnicos...

Más detalles

Qué necesito saber para tener mi sitio web en Internet?

Qué necesito saber para tener mi sitio web en Internet? Qué necesito saber para tener mi sitio web en Internet? Introducción Antes es importante tener en cuenta que Es importante considerar lo siguiente: Definir claramente tu actividad en Internet Establecer

Más detalles

Adicionalmente, en función de su objetivo, las Cookies puedes clasificarse de la siguiente forma:

Adicionalmente, en función de su objetivo, las Cookies puedes clasificarse de la siguiente forma: Cookies policy a) Utilización de Cookies y Web Bugs b) Tipología, finalidad y funcionamiento de las Cookies c) Cómo deshabilitar las Cookies y los Web Bugs en los principales navegadores d) Qué ocurre

Más detalles

La vida en un mundo centrado en la red

La vida en un mundo centrado en la red La vida en un mundo centrado en la red Aspectos básicos de networking: Capítulo 3 1 Objetivos En este capítulo aprenderá a: Describir cómo las funciones de las tres capas superiores del modelo OSI que

Más detalles

SISTEMAS DE INFORMACIÓN II TEORÍA

SISTEMAS DE INFORMACIÓN II TEORÍA CONTENIDO: EL PROCESO DE DISEÑO DE SISTEMAS DISTRIBUIDOS MANEJANDO LOS DATOS EN LOS SISTEMAS DISTRIBUIDOS DISEÑANDO SISTEMAS PARA REDES DE ÁREA LOCAL DISEÑANDO SISTEMAS PARA ARQUITECTURAS CLIENTE/SERVIDOR

Más detalles

Bajo Costo de Implementación y Soporte: Ofrecer un bajo costo de implementación y mantenimiento.

Bajo Costo de Implementación y Soporte: Ofrecer un bajo costo de implementación y mantenimiento. Documento de Referencia Una Única Solución que Integra Todas las Aplicaciones que su Empresa Requiere Tecnologizar los procesos financieros, operacionales y de gestión de su empresa, es sólo cuestión de

Más detalles

Servicio de VPN de la Universidad de Salamanca

Servicio de VPN de la Universidad de Salamanca Servicio de VPN de la Universidad de Salamanca Descripción del Servicio El servicio de VPN de la Universidad de Salamanca permite el acceso a recursos internos de la misma desde cualquier acceso a Internet

Más detalles

Sistemas Multimedia Distribuidos. Juan A. Sigüenza Departamento de Ingeniería Informática UAM

Sistemas Multimedia Distribuidos. Juan A. Sigüenza Departamento de Ingeniería Informática UAM Sistemas Multimedia Distribuidos Juan A. Sigüenza Departamento de Ingeniería Informática UAM Componentes de un Sistema Multimedia Distribuido Software de aplicación Almacenamiento de Documentos Almacenamiento

Más detalles

Sistema de Control de Accesos API-WIN

Sistema de Control de Accesos API-WIN El API-WIN es un, un conjunto de aplicaciones destinadas a controlar al personal interno y externo de una organización. Este sistema es el encargado de la administración de los accesos controlados por

Más detalles

Sistemas Operativos Windows 2000

Sistemas Operativos Windows 2000 Sistemas Operativos Contenido Descripción general 1 Funciones del sistema operativo 2 Características de 3 Versiones de 6 Sistemas Operativos i Notas para el instructor Este módulo proporciona a los estudiantes

Más detalles

Internet Information Server

Internet Information Server Internet Information Server Internet Information Server (IIS) es el servidor de páginas web avanzado de la plataforma Windows. Se distribuye gratuitamente junto con las versiones de Windows basadas en

Más detalles

WINDOWS 2008 5: TERMINAL SERVER

WINDOWS 2008 5: TERMINAL SERVER WINDOWS 2008 5: TERMINAL SERVER 1.- INTRODUCCION: Terminal Server proporciona una interfaz de usuario gráfica de Windows a equipos remotos a través de conexiones en una red local o a través de Internet.

Más detalles

Análisis de aplicación: TightVNC

Análisis de aplicación: TightVNC Análisis de aplicación: TightVNC Este documento ha sido elaborado por el Centro de Apoyo Tecnológico a Emprendedores bilib, www.bilib.es Copyright 2011, Junta de Comunidades de Castilla La Mancha. Este

Más detalles

Cliente Citrix ICA Windows CE Tarjeta de consulta rápida

Cliente Citrix ICA Windows CE Tarjeta de consulta rápida Cliente Citrix ICA Windows CE Tarjeta de consulta rápida Requisitos Para ejecutar el Cliente ICA Windows CE, debe disponer de lo siguiente: Un dispositivo basado en Windows CE Una tarjeta de interfaz de

Más detalles

Manual de Instalación. Sistema FECU S.A.

Manual de Instalación. Sistema FECU S.A. Manual de Instalación Sistema FECU S.A. Índice Requerimientos de hardware... 3 Requerimientos de software... 3 Bajar programas desde Internet... 4 Manual de Usuario... 5 Archivos de instalación FECU S.A....

Más detalles

Gestor de Contenidos CMS. Prof: Ing. Henrry Servitá

Gestor de Contenidos CMS. Prof: Ing. Henrry Servitá Gestor de Contenidos CMS Que es un CMS? CMS son las siglas de Content Management System, que se traduce directamente al español como Sistema Gestor de Contenidos. Como su propio nombre indica, es un sistema

Más detalles

PRESENTACIÓN TÉCNICA Y REQUISITOS DOCUMENTO EXTERNO

PRESENTACIÓN TÉCNICA Y REQUISITOS DOCUMENTO EXTERNO PRESENTACIÓN TÉCNICA Y REQUISITOS DOCUMENTO EXTERNO PRESENTACIÓN TÉCNICA Y REQUISITOS MANUAL Presentación Técnica y Requisitos www.kronotek.net 1 PRESENTACIÓN TÉCNICA Y REQUISITOS Tabla de contenido 1.

Más detalles

CAPÍTULO 4 ANÁLISIS DE IMPLEMENTACIONES

CAPÍTULO 4 ANÁLISIS DE IMPLEMENTACIONES CAPÍTULO 4 ANÁLISIS DE IMPLEMENTACIONES En el anterior capítulo se realizaron implementaciones en una red de datos para los protocolos de autenticación Kerberos, Radius y LDAP bajo las plataformas Windows

Más detalles

Trabajo TICO Unidad 2: Sistemas Operativos. Guillermo Jarne Bueno.

Trabajo TICO Unidad 2: Sistemas Operativos. Guillermo Jarne Bueno. Un Sistema Operativo es el software encargado de ejercer el control y coordinar el uso del hardware entre diferentes programas de aplicación y los diferentes usuarios. Es un administrador de los recursos

Más detalles

Emerson Network Energy Center, ENEC Lite, es. Multilenguaje. Navegación intuitiva. Multiusuario. Seguridad. Mantenimiento y control

Emerson Network Energy Center, ENEC Lite, es. Multilenguaje. Navegación intuitiva. Multiusuario. Seguridad. Mantenimiento y control Emerson Network Energy Center, ENEC Lite, es una aplicación para la gestión remota y local de sistemas de energía, baterías, corriente alterna, grupos electrógenos, SAIs, sistemas de refrigeración y demás

Más detalles

Lección 5: Bloc de notas Estudio de la aplicación Bloc de notas, utilizada para escribir sencillos documentos de texto de tamaño reducido.

Lección 5: Bloc de notas Estudio de la aplicación Bloc de notas, utilizada para escribir sencillos documentos de texto de tamaño reducido. Curso para conocer y aprender a manejar completamente el sistema operativo Microsoft Windows XP Professional, analizando desde el entorno del mismo hasta sus herramientas administrativas más complejas

Más detalles

Studium, Campus Virtual de la Universidad de Salamanca.

Studium, Campus Virtual de la Universidad de Salamanca. Studium, Campus Virtual de la Universidad de Salamanca. Contenidos 1 Qué es Studium 2 Instalación de Studium en USAL 3 Atención a los usuarios 4 Instalación Moodle. MoodleWindowsInstaller 5 Moodle portable

Más detalles

Guía de instalación de la carpeta Datos de IslaWin

Guía de instalación de la carpeta Datos de IslaWin Guía de instalación de la carpeta Datos de IslaWin Para IslaWin Gestión CS, Classic o Pyme a partir de la revisión 7.00 (Revisión: 10/11/2011) Contenido Introducción... 3 Acerca de este documento... 3

Más detalles

Plataforma e-ducativa Aragonesa. Manual de Administración. Bitácora

Plataforma e-ducativa Aragonesa. Manual de Administración. Bitácora Plataforma e-ducativa Aragonesa Manual de Administración Bitácora ÍNDICE Acceso a la administración de la Bitácora...3 Interfaz Gráfica...3 Publicaciones...4 Cómo Agregar una Publicación...4 Cómo Modificar

Más detalles

Producto. Información técnica y funcional. Versión 2.8

Producto. Información técnica y funcional. Versión 2.8 Producto Información técnica y funcional Versión 2.8 1 Índice: Tema Pág. Introducción a WOLOM 3 Diagrama de la solución WOLOM 3 Principales funciones de WOLOM 4 Módulos que componen WOLOM 4 WM: Wolom Maquetador

Más detalles

BASES DE DATOS OFIMÁTICAS

BASES DE DATOS OFIMÁTICAS BASES DE DATOS OFIMÁTICAS Qué es una Bases de Datos Ofimática?. En el entorno de trabajo de cualquier tipo de oficina ha sido habitual tener un archivo con gran parte de la información necesaria para el

Más detalles

Componentes de Integración entre Plataformas Información Detallada

Componentes de Integración entre Plataformas Información Detallada Componentes de Integración entre Plataformas Información Detallada Active Directory Integration Integración con el Directorio Activo Active Directory es el servicio de directorio para Windows 2000 Server.

Más detalles

MANUAL DE USUARIO ANTIVIRUS BANDA ANCHA

MANUAL DE USUARIO ANTIVIRUS BANDA ANCHA MANUAL DE USUARIO ANTIVIRUS BANDA ANCHA ÍNDICE 1 INTRODUCCIÓN... 4 1.1 ANTIVIRUS BANDA ANCHA... 4 1.2 ANTIVIRUS... 4 1.3 EFICACIA... 4 1.4 ACTUALIZACIONES... 4 2 REQUISITOS TÉCNICOS... 6 2.1 CONOCIMIENTOS

Más detalles

Programación de Sistemas

Programación de Sistemas Programación s Unidad 2 s Operativos y Programación Software Base Contenido Introducción a los s Operativos (SO) Definición y conceptos SO Visualización un sistema cómputo s distintos puntos vista Capas

Más detalles

App para realizar consultas al Sistema de Información Estadística de Castilla y León

App para realizar consultas al Sistema de Información Estadística de Castilla y León App para realizar consultas al Sistema de Información Estadística de Castilla y León Jesús M. Rodríguez Rodríguez rodrodje@jcyl.es Dirección General de Presupuestos y Estadística Consejería de Hacienda

Más detalles

Infraestructura Tecnológica. Sesión 2: Mejoras adicionales al servidor de archivos

Infraestructura Tecnológica. Sesión 2: Mejoras adicionales al servidor de archivos Infraestructura Tecnológica Sesión 2: Mejoras adicionales al servidor de archivos Contextualización Los servidores como cualquier equipo de cómputo pueden contar con varias mejoras con las que se pueden

Más detalles

Estándares para el Uso de Herramientas de Desarrollo y Plataformas de Aplicaciones Web

Estándares para el Uso de Herramientas de Desarrollo y Plataformas de Aplicaciones Web Secretaría de Planificación Estratégica Oficina de Informática Estándares para el Uso de Herramientas de Desarrollo y Plataformas de Aplicaciones Web VERSIÓN 4 Julio 2009 Índice 1. Generalidades... 3 1.1

Más detalles

ARQUITECTURA DE DISTRIBUCIÓN DE DATOS

ARQUITECTURA DE DISTRIBUCIÓN DE DATOS 4 ARQUITECTURA DE DISTRIBUCIÓN DE DATOS Contenido: Arquitectura de Distribución de Datos 4.1. Transparencia 4.1.1 Transparencia de Localización 4.1.2 Transparencia de Fragmentación 4.1.3 Transparencia

Más detalles

Análisis de aplicación: Virtual Machine Manager

Análisis de aplicación: Virtual Machine Manager Análisis de aplicación: Virtual Machine Manager Este documento ha sido elaborado por el Centro de Apoyo Tecnológico a Emprendedores bilib, www.bilib.es Copyright 2011, Junta de Comunidades de Castilla

Más detalles

Características del software

Características del software Características del software Descripción general de Fierro Fierro resuelve la operatoria diaria y la problemática de librerías y editoriales. Fierro fue gestado por gente que conoce el mercado del libro,

Más detalles

Capítulo VI. Conclusiones. En este capítulo abordaremos la comparación de las características principales y

Capítulo VI. Conclusiones. En este capítulo abordaremos la comparación de las características principales y Capítulo VI Conclusiones En este capítulo abordaremos la comparación de las características principales y de las ventajas cada tecnología Web nos ofrece para el desarrollo de ciertas aplicaciones. También

Más detalles

Unidad V. Infraestructura del comercio electrónico. M.C. Juan Carlos Olivares Rojas

Unidad V. Infraestructura del comercio electrónico. M.C. Juan Carlos Olivares Rojas Unidad V. Infraestructura del comercio electrónico M.C. Juan Carlos Olivares Rojas Agenda 5.1 Sistemas de comunicación 5.2 Sistemas de pago 5.3 Distribución y entrega 5.4 Interconexión de redes 5.5 El

Más detalles

Servicio de Informática Vicerrectorado de Tecnologías de la Información y la Comunicación

Servicio de Informática Vicerrectorado de Tecnologías de la Información y la Comunicación Vicerrectorado de Tecnologías de la Información y la Comunicación Conexión mediante Escritorio Remoto de Windows Última Actualización 16 de septiembre de 2013 Histórico de cambios Fecha Descripción Autor

Más detalles

Aplicaciones Móviles. Sesión 12: Acceso a datos

Aplicaciones Móviles. Sesión 12: Acceso a datos Aplicaciones Móviles Sesión 12: Acceso a datos Contextualización Los datos son actualmente elementos muy importantes, pues éstos definen características de uso de elementos en la informática, dan identidad

Más detalles

SCT3000 95. Software para la calibración de transductores de fuerza. Versión 3.5. Microtest S.A. microtes@arrakis.es

SCT3000 95. Software para la calibración de transductores de fuerza. Versión 3.5. Microtest S.A. microtes@arrakis.es SCT3000 95 Versión 3.5 Software para la calibración de transductores de fuerza. Microtest S.A. microtes@arrakis.es Introducción El programa SCT3000 95, es un sistema diseñado para la calibración automática

Más detalles

Peer-to-Peer (Punto a Punto) Cliente-Servidor

Peer-to-Peer (Punto a Punto) Cliente-Servidor Tipos de Redes Peer-to-Peer (Punto a Punto) Cliente-Servidor Donde es apropiada la Peer_to_Peer Son buena elección para entornos donde: Hay menos de 20 usuarios. Los usuarios están situados todos en el

Más detalles

Administración de la producción. Sesión 2: Sistema Operativo (Microsoft Windows XP)

Administración de la producción. Sesión 2: Sistema Operativo (Microsoft Windows XP) Administración de la producción Sesión 2: Sistema Operativo (Microsoft Windows XP) Contextualización El sistema operativo es el programa principal de la computadora que controla los procesos informáticos

Más detalles

Herramientas Informáticas para la Documentación Práctica 1. Introducción al navegador Netscape

Herramientas Informáticas para la Documentación Práctica 1. Introducción al navegador Netscape Herramientas Informáticas para la Documentación Práctica 1. Introducción al navegador Netscape Introducción y objetivos De modo muy resumido Internet es una red que interconecta redes de ordenadores. Conectándose

Más detalles

FileMaker Pro 12. Uso de una Conexión a Escritorio remoto con FileMaker Pro 12

FileMaker Pro 12. Uso de una Conexión a Escritorio remoto con FileMaker Pro 12 FileMaker Pro 12 Uso de una Conexión a Escritorio remoto con FileMaker Pro 12 2007-2012 FileMaker, Inc. Reservados todos los derechos. FileMaker, Inc. 5201 Patrick Henry Drive Santa Clara, California 95054

Más detalles

APOLO GESTION INTEGRAL.

APOLO GESTION INTEGRAL. APOLO GESTION INTEGRAL. APOLO Gestión es una aplicación realizada en Visual Studio, y apoyada en una potente base de datos SQL, que le proporciona grandes ventajas a la hora de trabajar tanto sobre redes

Más detalles

Introducción a la Firma Electrónica en MIDAS

Introducción a la Firma Electrónica en MIDAS Introducción a la Firma Electrónica en MIDAS Firma Digital Introducción. El Módulo para la Integración de Documentos y Acceso a los Sistemas(MIDAS) emplea la firma digital como método de aseguramiento

Más detalles

Visualización y modelado de elementos geográficos en dispositivos móviles. Capítulo 5: Aplicaciones cliente

Visualización y modelado de elementos geográficos en dispositivos móviles. Capítulo 5: Aplicaciones cliente Capítulo 5: Aplicaciones cliente 46 5.1 La aplicación cliente en la Pocket PC La aplicación desarrollada para el cliente en un dispositivo móvil como corresponde a la Pocket PC necesita una capa muy delgada

Más detalles

Configuracion Escritorio Remoto Windows 2003

Configuracion Escritorio Remoto Windows 2003 Configuracion Escritorio Remoto Windows 2003 Instalar y configurar servicio de Terminal Server en Windows 2003 Fecha Lunes, 25 diciembre a las 17:04:14 Tema Windows (Sistema Operativo) Os explicamos cómo

Más detalles

Edición de Ofertas Excel Manual de Usuario

Edición de Ofertas Excel Manual de Usuario Edición de Ofertas Excel Manual de Usuario Alfonso XI, 6 28014 Madrid F(+34) 91 524 03 96 www.omie.es Ref. MU_OfertasExcel.docx Versión 4.0 Fecha: 2012-11-26 ÍNDICE 1 INTRODUCCIÓN 3 2 CONSIDERACIONES DE

Más detalles

Proceso Unificado de Rational PROCESO UNIFICADO DE RATIONAL (RUP) El proceso de desarrollo de software tiene cuatro roles importantes:

Proceso Unificado de Rational PROCESO UNIFICADO DE RATIONAL (RUP) El proceso de desarrollo de software tiene cuatro roles importantes: PROCESO UNIFICADO DE RATIONAL (RUP) El proceso de desarrollo de software tiene cuatro roles importantes: 1. Proporcionar una guía de actividades para el trabajo en equipo. (Guía detallada para el desarrollo

Más detalles

Descripción. Este Software cumple los siguientes hitos:

Descripción. Este Software cumple los siguientes hitos: WWWMONITORDBACOM Descripción Este Software cumple los siguientes hitos: a- Consola de Monitoreo b- Envío de Alertas (correo, SMS) c- Gestión de Eventos desatendidos (sea capaz ejecutar script de solución

Más detalles

Información de Producto:

Información de Producto: Windows Server 2008 Foundation La nueva tecnología rentable de Windows Server 2008 Foundation La tecnología confiable y comprobada de Windows Server Foundation proporciona una base para ejecutar las aplicaciones

Más detalles

Eurowin 8.0 SQL. Manual de la FIRMA DIGITALIZADA

Eurowin 8.0 SQL. Manual de la FIRMA DIGITALIZADA Eurowin 8.0 SQL Manual de la FIRMA DIGITALIZADA Documento: me_firmadigitalizada Edición: 02 Nombre: Manual de la Firma Digitalizada en Eurowin Fecha: 19-05-2011 Tabla de contenidos 1. FIRMA DIGITALIZADA

Más detalles

Instrucciones de instalación de IBM SPSS Modeler Server 16 para Windows

Instrucciones de instalación de IBM SPSS Modeler Server 16 para Windows Instrucciones de instalación de IBM SPSS Modeler Server 16 para Windows Contenido Instrucciones para la instalación.... 1 Requisitos del sistema........... 1 Instalación............... 1 Destino...............

Más detalles

Resumen de la solución SAP SAP Technology SAP Afaria. Gestión de la movilidad empresarial para mayor ventaja competitiva

Resumen de la solución SAP SAP Technology SAP Afaria. Gestión de la movilidad empresarial para mayor ventaja competitiva de la solución SAP SAP Technology SAP Afaria Gestión de la movilidad empresarial para mayor ventaja competitiva Simplificar la gestión de dispositivos y aplicaciones Simplificar la gestión de dispositivos

Más detalles

Mi propuesta consiste en crear un portal Web que contemple las siguientes funcionalidades:

Mi propuesta consiste en crear un portal Web que contemple las siguientes funcionalidades: Propósito del prototipo: Mi propuesta consiste en crear un portal Web que contemple las siguientes funcionalidades: 1º. Mostrar noticias y eventos propios del grupo de personas que administren la Web.

Más detalles

TPV VIRTUAL O PASARELA DE PAGOS DE CAJASTUR

TPV VIRTUAL O PASARELA DE PAGOS DE CAJASTUR TPV VIRTUAL O PASARELA DE PAGOS DE CAJASTUR El TPV (Terminal Punto de Venta) Virtual es un producto dirigido a empresas y comercios, con tienda en internet, que permite el cobro de las ventas realizadas

Más detalles

Notas para la instalación de un lector de tarjetas inteligentes.

Notas para la instalación de un lector de tarjetas inteligentes. Notas para la instalación de un lector de tarjetas inteligentes. Índice 0. Obtención de todo lo necesario para la instalación. 3 1. Comprobación del estado del servicio Tarjeta inteligente. 4 2. Instalación

Más detalles

pymegnu v2.0 PRESENTACIÓN DE PRODUCTOS

pymegnu v2.0 PRESENTACIÓN DE PRODUCTOS PRESENTACIÓN DE PRODUCTOS pymegnu v2.0 1 INTRODUCCIÓN Nuestros sistemas 100% web le permitirán poder obtener todas las ventajas competitivas que ofrece Internet, como la disponibilidad de tener sus sistemas

Más detalles

Eficiencia en la Automatización y Gestión de Servicios

Eficiencia en la Automatización y Gestión de Servicios Eficiencia en la Automatización y Gestión de Servicios GESTIÓN EFECTIVA DE SERVICIOS CON SERVICETONIC Hoy en día las empresas están obligadas a hacer más con menos recursos y como consecuencia de ello

Más detalles

OpenProdoc. ECM Open Source

OpenProdoc. ECM Open Source OpenProdoc ECM Open Source Índice Visión General Arquitectura Funciones Seguridad Administración Requerimientos Evolución Visión General OpenProdoc es un gestor documental de código abierto. Cuenta con

Más detalles

INSTALACIÓ N A3ERP. Informática para empresas INTRODUCCIÓN CONSIDERACIONES GENERALES DE LA INSTALACIÓN PAQUETES DE INSTALACIÓN PREDEFINIDOS

INSTALACIÓ N A3ERP. Informática para empresas INTRODUCCIÓN CONSIDERACIONES GENERALES DE LA INSTALACIÓN PAQUETES DE INSTALACIÓN PREDEFINIDOS Página 1 de 20 INSTALACIÓ N A3ERP INTRODUCCIÓN La instalación de a3erp v9 ha sufrido una trasformación importante respecto a sus versiones anteriores. Cualquier instalación exige la existencia de un pc

Más detalles

Sumario Instalación MDT V5.3... 1

Sumario Instalación MDT V5.3... 1 Sumario Instalación MDT V5.3... 1 Requerimientos del Sistema... 1 Menú de Inicio... 2 Proceso de Instalación... 3 Después de la instalación... 4 Colocación de la Llave de Protección (USB)... 4 Colocación

Más detalles

Requerimientos de tecnología para operar con Tica. Proyecto TICA

Requerimientos de tecnología para operar con Tica. Proyecto TICA Requerimientos de tecnología para operar con Tica Proyecto TICA Costa Rica, Agosto de 2005 Tabla de Contenido Requerimientos Técnicos para Operar con Tica 3 1. Acceso a Internet 3 2. Escaneo de imágenes

Más detalles

Arquitectura de sistema de alta disponibilidad

Arquitectura de sistema de alta disponibilidad Mysql Introducción MySQL Cluster esta diseñado para tener una arquitectura distribuida de nodos sin punto único de fallo. MySQL Cluster consiste en 3 tipos de nodos: 1. Nodos de almacenamiento, son los

Más detalles