Redes Globales de Información. Transmisión de datos Multimedia

José Manuel Moreno Puertas

DNI: 45100013-D

email: jmp753@alboran.ual.es

Almería, 20 de Junio de 2003

Resumen

En este documento se pretende reflejar el trabajo realizado para la asignatura de Redes Globales de la Información, consistente en transmisión de datos multimedia por la red.

Índice general

1. Introducción al proyecto 2

2. Aplicación 3

2.1. Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.1.1. MultimediaServerRMI.java . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.2. MultimediaObjectRMI.java . . . . . . . . . . . . . . . . . . . . . . 4 2.1.3. MultimediaInterfaceRMI.java . . . . . . . . . . . . . . . . . . . . . 5 2.1.4. Transmit.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 2.1.5. RTPSocketAdapter.java . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.6. Util.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2. Cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.2.1. Interfaz Gráfica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2.2. Recept.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2.3. PlayerWindow.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.2.4. PlayerPanel.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3. Problemas encontrados 13

A. Herramientas utilizadas 14

A.1. Remote Method Invocation (RMI) . . . . . . . . . . . . . . . . . . . . . . . 14

A.1.1. Descripción RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 A.2. Java Database Connectivity (JDBC) . . . . . . . . . . . . . . . . . . . . . 15

A.2.1. Descripción JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 A.3. Java Media FrameWork (JMF) . . . . . . . . . . . . . . . . . . . . . . . . 16

A.3.1. Descripción JMF . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 A.3.2. Utilización de JMF . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

A.4. Abstract Window Toolkit (AWT) . . . . . . . . . . . . . . . . . . . . . . . 21

A.4.1. Descripción de AWT . . . . . . . . . . . . . . . . . . . . . . . . . . 21 A.5. Contenido del CD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

Capítulo 1

Introducción al proyecto

\underline{Proyecto}

El proyecto que se plantea es el desarrollo de un sistema de transmisión de

audio y video por la red (streaming). Para ello se ha trabajado con el software de Sun Microsystem JMF (Java Media FrameWork), que nos proporciona la transmisión de datos multimedia, el JDK la versión 1.4.1, RMI (Remote Method Invocation), utilizado para el control de la aplicación , JDBC (Java DataBase Connectivity), que nos propociona la conexión a bases de datos y AWT (Abstract Window Toolkit) para el desarrollo de una pequeña interfaz gráfica en el cliente (Para mayor infomación sobre las herramientas anteriores ver el anexo).

A un nivel más bajo se puede decir que la aplicación corre sobre el protocolo

RTP (Real Time Protocol)

\underline{La Idea}

La idea que se intenta porner de manifiesto es : Una máquina remota nos ofrece

sus servicios como servidor de datos multimedia, a los que accederemos desde distintos clientes. Si este servidor y este cliente mencionados son ’levantados en la misma máquina tendremos una ’Comunicación multimedia’ donde no tenemos un cliente y un servidor predefinidos, lo que tenemos son ’máquinas virtuales’ con la capacidad de transmitir y recibir datos.

\underline{Servidor}

El servidor implementa una interfaz de conexión a una base de datos mediante

JDBC, y una clase Transmit.java que es la que se encarga que enviar los datos por la red.

\underline{Cliente} El cliente implementa un receptor de datos mediante la clase Recept.java El control de ambos es gestionado mediante RMI.

Aplicación

La aplicación como ya se ha dicho se compone de un cliente y un servidor cuyas

clases más importantes pasamos a explicar a continuación.

\underline{Nota Importante:} Para que la aplicación funcione correctamente debemos ejecutarla bajo Windows, y hacer una conexión con el ODBC con un alias ’BdatosMultimedia’ asociandolo a la ruta donde tengamos la base de datos que hay en el servidor. Antes de utilizarla debemos modificar las rutas de los archivos en la base de datos.

2.1. Servidor

El servidor es el encargado primero de poner a disposión del cliente ciertas

funciones que permitan al cliente actuar con este. Esta funciones son puesta por el servidor a disposión del cliente mediante RMI. La ejecución de este se produce en modo consola.

Las clases del servidor son

1. \underline{MultimediaServerRMI.java} ’Clase que inicia el servidor de datos’

2. \underline{MultimediaObjetcRMI.java} ’Clase que implementa las funciones y procedimientos tanto los definidos como remotos como los locales’

3. \underline{MultimediaInterfaceRMI.java} ’Clase Interfaz donde se encuentran las funciones y los procedimientos a compartir con el cliente

4. \underline{Transmit.java} ’Clase que se encarga de desglosar los archivos de audio y video, y además de lanzar la transmisión de los datos

5. \underline{RTPSocketAdapter.java}, clase que junto con Transmit son las dos clases más importantes del servidor. Además esta clase es la que prepara los Sockets para ser abiertos.

6. \underline{Util.java}, clase encargada de la conexión a la base de datos mediante JDBC y gestiona todo lo relacionado con las consultas

2.1.1. MultimediaServerRMI.java

Clase encargada de iniciar la aplicación servidora, como vemos lo que hace es

instanciar y registrar en el servicio de nombres un instancia de la clase MultimediaOjectRMI.

import java.rmi.*; import java.rmi.server.*;
public class MultimediaServerRMI {
public static void main(String args[])
 {
 try{
    System.out.println("Activando servidor...");
    //se instala el controlador de seguridad
    if(System.getSecurityManager()==null)
      {
      System.setSecurityManager( new RMISecurityManager());
      }
    MultimediaObjectRMI objRemoto = new MultimediaObjectRMI();
    Naming.rebind("ObjetoMultimedia", objRemoto);
    System.out.println("     ...OK!");
   }catch(Exception e) {
     e.printStackTrace();
     }
    }
 }

2.1.2. MultimediaObjectRMI.java

Clase donde se encuentra la implementación de todos los métodos del servi-

dor tanto remotos como locales(Tengase en cuenta que los métodos remotos pueden ser utilizados como locales).

public void Conecta()
//Método para establecer conexión con la base de datos
//Hace uso de la clase Util (Se explicará posteriormente).
public void Desconecta()
//Método para cerrar la conexión con la base de datos
//del servidor.
public String construyeOrdenTodos()
//Método que construye la sentencia SQL que devuelve todos los
//datos del servidor.

public String obtenerBusquedaTodos() throws RemoteException
//Método que puede ser utilizado de forma remota ejecuta la consulta
//que ha sido contruida anteriormente por construyeOrdenTodos().
public Vector Resultado(ResultSet valores)
//Método que devuelve un vector de vectores con el resultado de
// la consulta.
public Vector obtenerBTodos() throws RemoteException
//Método que  devuelve un vector de vetores con el resultado de
//la consuta.(Método ejectuable de forma remota)
public String EnviarArchivo(String fichero, String destinoIP,
 String puerto, int Tipo) throws RemoteException
//Método que trasmite un archivo, le pasamos como parametro el
//nombre y la dirección donde ha de enviarlo, asi como el tipo de
//archivo, pista de audio ó video sueltas tipo 1, archivo de
//video con audio tipo 2, cualquier trasmisión de los
//perifericos como la cámara tipo 1.(Remoto)
public String UsarPuerto()throws RemoteException
//Método que devuelve el puerto que podemos usar para realizar la
//conexión.

La gestión hecha de los puertos es muy simple ya que simplemente se incrementa el puerto de conexión cada vez que se establece una, comenzando en el 1050 para que no haya complicaciones con los S.O’s y finaliza en el 32768 donde vuelve a intentar conger el puerto 1050. Aunque esta gestión es bastante pobre después el se evita que dos máquinas intenten acceder al mismo puerto a la vez, y si el puerto esta ocupado sencillamente no se realiza el envio.

public void PararTransmision()throws RemoteException
//Método que para la transmisión (Método Remoto).

2.1.3. MultimediaInterfaceRMI.java

Interfaz de acceso a los métodos remotos de la clase MultimediaObject.java.

import java.rmi.*;
import java.util.*;
public interface MultimediaInterfaceRMI extends Remote
{
String obtenerBusquedaTodos() throws RemoteException;
String obtenerBusquedaSeleccion(String fechaIni, String fechaFin,

  int tamMin, int tamMax, String tipo) throws RemoteException ;
 Vector obtenerBTodos() throws RemoteException;
 String EnviarArchivo(String fichero, String destinoIP, String puerto,
  int Tipo) throws RemoteException;
 String UsarPuerto()throws RemoteException;
 void PararTransmision()throws RemoteException;
 }

2.1.4. Transmit.java

Es una de las clases más importantes ya que es la que se va a encargar de

enviar el archivo, desglosandolo primero en distintas pistas. Para ver esta clase nos vamos a detener algo más que en las otras.

 public Trasmit(MediaLocator locator, String ipAddress, String pb)
 //Constructor de la clase

Los parametros que le pasamos son un MediaLocator, que se asemeja a la lo-

calización de lo que queremos trasmitir, por ejemplo: Si queremos trasmitir un archivo de video el MediaLocator sería file:/localización del archivo. Si queremos trasmitir directamente de la targeta de sonido MediaLocator seria DirectSound:/, si queremos la cámara vfw://0 y así con todos los dispositivos que JMF pueda reconocer. ipAddress es la dirección de destion y pb es el puerto de comienzo de transmisión.

 public synchronized String start()
 //Crea un processor (ver Anexo JMF) y e inicia la transmisión de
 //del archivo indicado en el contructor.

Esta función agrupa los dos principales processos de la trasmisión, createPro-

cessor y createTrasmiter que serán explicados posteriormente con más detalle; createProcessor lo que hace es crear el processor y llevarlo hasta su estado realized, este processor es encargado de procesar la información que va a ser trasmitida, y CreateTransmiter es el encargado de habilitar los ’sockets UDP’ y comenzar la transmisión.

 public void stop()
 //Para la transmisión si esta ya ha comenzado
 private String createProcessor()
 //Crea el processor que va a procesar los datos de entrada del
 //archivo, dispositivo, http etc...

Este método además de crear el processor, busca el formato de las pista (audio y

video) que hay en el ’Medialocator’ que se le pasa y las transforma a un formato soportado por JMF para el transporte sobre el protocolo RTP (Ver anexo Formatos Soportados). También ajusta los parametros para la transmisión de video en formato JPEG y H621 ya que estos formatos solamente pueden ser transmitidos con unos tamaños determinados.

private String createTransmitter()
//Abre una transmisión para el fichero

Es método captura las distintas pistas, ya convertidas en formato soportado por

JMF/rtp, crea sockets UDP utilizando la clase RTPSocketAdapter.java, y seguidamente lanza tantos streams como pistas haya. Para cada stream debemos tener encuenta que se lanzan dos puertos uno para la transmisión RTP y otro para el control de esta RTCP.

Format checkForVideoSizes(Format original, Format supported)
//Ajusta los tama~ nos del video, ya que no todos los tama~ nos
//están permitidos por JMF
void setJPEGQuality(Player p, float val)
//Ajusta la calidad de video JPEG lo que va a indicar cuantas
//frecuencias van a ser enviadas para cada imagen, para optimizar
//la transmisión.
private synchronized boolean EsperarEstado(Processor p, int state)
//Espera a que el processor pase por el estado indicado como
// parametro

El processor debe pasar por distintos estados, sin completar el estado actual

no puede pasar a los siguientes debido a que no esta preparado, con esta función lo que hacemos es asegurarnos de que el processor ha llegado al estado deseado.

class StateListener implements ControllerListener,
 SendStreamListener, SessionListener, RemoteListener
//Clase que implementa los distintos eventos de la transmisión

Clase que implementa las distintas acciones producidas por los eventos de la

transmisión (Ver Anexo JMF).

2.1.5. RTPSocketAdapter.java

Clase creada para realizar los envios en sockets RTP, crea las distintas conexiónes RTP y RTCP, ha más maneras de realizar envios (Ver anexo JMF Transmisiones), pero esta es la que mejor soporta fallos en la red.

public RTPSocketAdapter(InetAddress addr, int port, int ttl)
 throws IOException
//Constructor de la clase, guarda la dirección de destino, el
//puerto de envio, y el ttl del envio.
 public PushSourceStream getDataInputStream() throws IOException
//Habilita un stream de entrada para recibir datos RTP.

Esta función lo que realmente hace es reservar espacio para los datos del stream

de entrada.

public OutputDataStream getDataOutputStream() throws IOException {
//Habilita un stream de salida para enviar datos RTP.
public PushSourceStream getControlInputStream() throws IOException
//Habilita un stream de salida para enviar datos de control RTCP.
 public OutputDataStream getControlOutputStream() throws IOException
//Habilita un stream de entrada para recibir datos de control RTCP.
public void close()
//Cierra todos los streams
class SockOutputStream implements OutputDataStream
//Clase que crea los Streams de salida
public SockOutputStream(DatagramSocket sock, InetAddress addr, int
port)
//Contructor de la clase
public int write(byte data[], int offset, int len)
//Método que crea un socket de envio.
class SockInputStream extends Thread implements PushSourceStream
//Clase que implementa los streams de entrada de datos.
public int read(byte buffer[], int offset, int length)
//Método para recibir los datos que son scretos en un Datagrama.
public void run()
//Sobreescribimos el método run para que nos indique las llegadas
//de datos.

2.1.6. Util.java

Clase que se utiliza para la conexión con la base de datos, y lee los distintos

parametros de conexión del archivo ServidorMultimedia.dat.

public static void leeFicheroIni()
//Lee el fichero con los parametros de conexión con la base de
//datos.
public static String devuelveControlador()
//Devuevle el controlador asociado a JDBC
public static String devuelveDSource() ()
//Devuevle el alias del ODBC donde se encuentra la base de datos
public static String devuelveBD()
//Devuevle el nombre de la base de datos

Figura 2.1: Video y Audio

Figura 2.2: Configuración

2.2. Cliente

El cliente es el encargado de pedir y recibir los datos que envia el servidor,

debe conocer la dirección IP del servidor de datos. Establecer la conexión mediante RMI, acceder a los datos de la base de datos, y pedir el envio del archivo. La implementación del cliente esta realizada mediante una interfaz gráfica, una primera ventana donde realizamos la selección del servidor a conectar y un botón para conectar(Ver Figura 2.1), en la pestaña Configuración (Ver Figura 2.2), podemos introducir servidores nuevos, con el puerto de conexión por defecto, pulsando en el boton \underline{Guardar}. Si pulsamos en el botón \underline{Actualizar} aparecerá una ventana actualizar donde podremos borrar los servidores que no nos interesen (Ver Figura 2.3). En la ventana principal se encuentra el botón \underline{Buscar Archivo} pulsandolo podemos ver los archivos de la base de datos del servidor seleccionado.(Ver Figura 2.4)

CAPÍTULO 2. APLICACIÓN 10

Figura 2.3: Actualizar Figura 2.4: Archivos Servidor

2.2.1. Interfaz Gráfica

Como el lector puede suponer hay varias clases que sirven para crear la insterfaz

gráfica que solamente se van a enumerar ya que no se ha utilizado ningún componente que no sea de uso común.

1. \underline{Application1.java} Clase que inicia la aplicación

2. \underline{FrameError.java} junto con Error.java, simplemente lanza Frames que muestran los distintos errores.

3. \underline{Frame1} Crea la ventana principal de la aplicación (Ver Figuras 2.1 y 2.2).

4. \underline{Frame 3} Crea la ventana donde se visualizan los archivos del servidor. Y realiza la conexión con el servidor y petición del archivo.

5. \underline{Frame 4} Crea la venta sobre la que se actualiza el listado de servidores.

2.2.2. Recept.java

Clase que se encarga de recibir los distintos streams mandados por el servidor, y

los reproduce. También hace uso de la clase RTPSocketAdapter.java, vista anteriormente para el servidor. Implementa los distintos eventos para la recepción de streams y el control sobre esta (Eventos RTP y RTCP). (Ver Anexo JMF)

 public Recept(String sessions[], long BufferTime, int tipo,
 MultimediaInterfaceRMI objMultimedia)
 //Constructor de la clase

Al constructor de la clase le pasamos unos paramentros de entrada que son la IP

de procedencia de los datos, el medialocator de procedencia y el puerto, long BufferTime, es el Tiempo minimo para reproducir, para evitar variaciones en el ’Jitter’, el tipo es el tipo de archivo (audio/video) y el último parametro es el objeto RMI por si huviera que para la transmisión de forma inesperada por fallo en la recepción.

 protected boolean initialize()
 MultimediaInterfaceRMI objMultimedia)
 //Constructor de la clase

Incia el cliente y habilita streams de entrada para recoger los datos (Tantos

streams como sea el tipo del archivo). Antes de habilitar los streams espera por un periodo de 30 segundos la llegada de cada uno de ellos si la recepción no se produce se corta la transmisión, y se liberan los recursos.

 protected void close()
 //liberar los recursos reservados para la recepción.

En esta clase hay que comentar, uno de los eventos de la transmisión ’Re-

ceiveStreamEvent’ ya que en función de este evento se va a producir la reserva de recursos y la visualización.

 public synchronized void update(ReceiveStreamEvent evt)
 //Evento que se lanza cuado se recive un nuevo stream

En función de la recepción de los distintos streams, de los cuales conocemos el

número de antemano, se van reservando recursos para los distintos players (Ver Anexo JMF), a los que se hace pasar por sus distintos estados hasta que se puede reproducir.

2.2.3. PlayerWindow.java

Clase que se encarga de almacenar el player que corresponde a cada stream.

2.2.4. PlayerPanel.java

Clase que se encarga de añadir al player componentes visuales, si los tiene, y

distintos controles, como pueden ser controles de sonido etc …

Problemas encontrados

Los problemas encontrados son a la hora de utilizar JMF/rtp con respecto a

algunos formatos, ya que en su documentación por ejemplo indica que es posible transmitir archivos mp3, lo cual es, después de muchas pruebas incluso con el software diseñado por Sun Microsystem, y visitar algunos foros, totalmente incierto.

Aunque hay que reconocer la potencia de la herramienta y el importante ahorro

de trabajo, también me he encontrado con el problema de que los videos sobre todo vienen codificados de distintas maneras, según MPEG-4, formatos AVI alterados, que buscando el la página de Sun Microsystem indican, que si la máquina a la que van dirida los datos posee los codecs para decodificar la información, no hay problema, lo cual después de una serie de pruebas puedo decir, que es falso. A no se que lo que se haga sea enviar el archivo y después reproducirlo, pero este tipo de transmisión no es en tiempo real, es simplemente una descarga de una archivo y visualización.

Hay una versión de JMF para Linux, pero después de hacer algunas pruebas, y que la aplicación no funcionase bien sin una casusa justificada (aparente), tuve que cambiar a windows.

En Resumen La herramienta JMF está muy bien para reproducir videos en

forma local, facilita la captura de los distintos dispositivos, pero con respecto a su versión de transmisión en tiempo real esta muy sujeto a los formatos que soporta y todavía le queda un largo camino, por recorrer.

Apéndice A

Herramientas utilizadas

A.1. Remote Method Invocation (RMI)

RMI es un mecanismo de Java que permite la comunicación enter dos objetos,

estando estos presentes cada uno en una máquina virtual distinta en misma máquina física, o incluso en m´ ´ aquinas virtuales distintas presentas cada una en una máquina física distinta.

A.1.1. Descripción RMI

Las aplicaciones RMI están compuestas casi siempre de dos programas separa-

dos: un programa cliente y uno servidor. Una aplicación sevidor típica crea varios objetos remotos, hace que las referencias a ellos sean accesibles y espera que los lcientes invoquen métodos sobre esos objetos remotos. Una aplicación cliente típica obtienen una referencia remota a uno o varios de los objetos remostos regsitrados en el servidor y entonces invoca métodos sobre dichoso objetos. RMI proporciona el mecanismo por el cual el cliente y el servidor se comunicacn y se pasan información entre ellos. Las aplicaiones citadas reciben a menudo el nombre de aplicaiones de objetos distribuidos. Una aplicacíón de objetos distribuidos necesita básicamente lo siguiente para su funcionamiento:

1. Localizar objetos remotos (registrados mediante rmiregistry)

2. Comunicarse con objetos remotos

3. Cargar los byte-codes de las clases de los objetos que son pasados.

Un objeto pasa a ser remoto implementando una interfaz remota, la cual tiene

las siguientes características :

1. Una interfaz remota extiende la interfaz Java java.rmi.Remote.

2. Cada método de la interfaz delcara java.rmi.RemoteException en su claúsula throws, además de alguna excepción más especifica de la aplicación.

RMI trara un objeto remoto de uanf roma diferente a como trata un objeto no

remooto, cuando el objetos es passado de una máquina vietual a otra. En lugar de hacer una copia de la implemtnación de objeto remoto en la máquina virtual receptora, RMI pasa un stub rmoto po r cada objeto rmoto que se desa ofrecer. El stub actua como el representante local, o proxy, para el objeto remoto y se trata básicamente de una referencia remota para ser usada por el objeto invocador. El objeto invocador llama a un método en el stub local, y es este último el responsable de llevar a cabo la llamada al método sobre el ojbto remoto. Un stub para un objeto remoto implemnt6a el mismo conjunto de interfaaces remotas que el objeto remoto implementa.

A.2. Java Database Connectivity (JDBC)

JDBC es el paquete de Java (incluido en el JDK) que proporciona acceso a

bases de datos a aplicaciones escritas en código Java. Se trata de una herramienta que poroporcinana acceso SQL genérico a bases de dtos, mediante una interfaz uniforme por encima de uang ran veariedadd de módulos de conectividad a bases de datos.

A.2.1. Descripción JDBC

JDBC hace posible el desarrollo de aplicacones de bases de datos independi-

entes de la paltaforma. La única prmisa que se imponen al fabricante del sistema gestro de bases de dastos es que ofrezca un conjuitno de calses, escrito en Java, al que se lle llama controlador JDBC. Las clases que compoenen los cotnroladorsw JDBC son clases abstractas que implementan para un sistema gestor de bases de dtos contrcreto los métodos del paquete de Jva java.sql. Estos métodos sirvenm para ejectuar perticiones SQL, que por tanto pueden ser enviadas desde una apliación Java, ser traducidas por le controlador JDBC al dialecto propio del sistema gestor de bases de datos par el que esté preparado, y ejecutadas por el sistema gestor. A su vez, tmabién se dispone de una serie de clases abstractas para recoger la información que este sistema gestor devuelve.

Es posible lanzar a través de JDBC peticiones al sistema gestor de bases de

datos que no respeten el estaándar SQL yu que incluso ni tan siquiera constituyan parte de SQL, sino que pertenezcan a un conjutno de intrucciones propietarias de este sistema. Este funcionamiento permite sacar partido a las funcionalidades propias de un sistema gestor de bases de datos concreto. Además, al no obligar al cumplimiento de una determinada grámática, JDBC abarca potencialmente a un conjunto bastante mayor de sistemas de bases de datos.

Para que una apliación escrita en Java se pueda comunicar con una base de

datos determinada a través de JDBC, se necesita el controlador JDBC que convierta las órdenes que se le van a transmitir en Java en comandos legibles para esa base de datos en concreto. Existen varios tipos de controladores JDBC para conectarse mediante Java a un sistema gestor de bases de datos, pero enre ellos, el más utilizado es el puente JDBC-ODBC. Este controlador que se ha empleado en el desarrollo de la aplicación para que el cliente pueda consultar la base de datos del servidor. El puente JDBC-ODBC no es más que un controlador JDBC par bases de datos a las que se accede a través del estándar ODBC, de forma que las aplicaciones Java puedan comunicarse con sistemas de bases de datos basados en ODBC.

En la aplicación JDBC ha sido utilizado el la clase del servidor Util.java

A.3. Java Media FrameWork (JMF)

JMF es le paquete de Java (no incluido en el JDK) orientado a la integración

de sonido e imagen en aplicaciones Java. Mediante JMF es posible reproducir datos multimedia tanto de forma local como a través de la red desde una palicaión escrita en Java.

A.3.1. Descripción JMF

JMF es una herramienta independiente de la plataforma que permite la reproducción de una gran variedad de datos multimedia desde una aplicación Java, está diseñado para soporta la mayor parte de los tipos de datos multimedia existentes, tales como MPEG, AVI, WAV, MP3, MIDI, RMF, AU. etc … Usando JMF se pueden sincronizar y presentar datos multimedia procedentes de diferentes fuentes. La API JMF proporciona una abstracción que esconde los detalles de implementación para el desarrollador, trabaja con diferentes protocolos y mecanismos de entrega de datos, como multitud de tipos de datos multimedia, y proporciona un modelo de eventos para la comunicación asíncrona entre reproductores JMF y aplicaciones Java.

A.3.2. Utilización de JMF

Dentro de esta sección se van a comentar las distintas clases utilizadas para desarrollar la aplicación, para entrar en más detalle remitirse a la documentación de JMF incluida en el CD.

\underline{Clase DataSource} Esta clase se encarga de encapsular la localización, el protocolo de transferencia y el software necesarios para la adquisición. Por lo tanto una vez obtenido un DataSource no se puede asociar a otra fuente de datos.

Se construye a partir de un URL o un MediaLocator. Un MediaLocator es como

un URL pero se puede construir aunque no se encuentre instalado en el sistema el handler para el protocolo especificado.

Para la construcción de estos objetos hace falta localizar los datos, por ello su

creación por parte del programador sería muy complicada. Para facilitar este extremo, lo que se hace es pedir al sistema el DataSouce necesario a partir de la URL o el MediaLocator a través de la clase Manager.

\underline{Clases Player y Processor} Un Player es un objeto encargado de procesar cierto flujo de datos multimedia y presentarlo en su preciso momento. La forma de presentación y los recursos necesarios dependen del tipo de media que contenga el flujo.

Como en el caso anterior, no se utiliza el constructor para crear objetos de esta clase sino que se llama a una función (createPlayer()) que busca en el sistema los componentes adecuados y crea el Player que se necesita en cada momento.

Para obtener el flujo de datos se utiliza un objeto DataSource que se ’engancha’ a la entrada del Player. En el caso de que a la función createPlayer() le pasemos un URL o un MediaLocator, esta construye primero el DataSource y luego el Player.Para obtener el flujo de datos se utiliza un objeto DataSource que se ’engancha’ a la entrada del Player. En el caso de que a la función createPlayer() le pasemos un URL o un MediaLocator, esta construye primero el DataSource y luego el Player.

Para utilizar un Player es necesario que obtenga recursos del sistema pro lo que pasa por varios estados antes de poder reproducir los datos multimedia, sin embargo, el usuario de JMF no debe preocuparse de esta gestión ya que hay funciones que en un sólo paso crean un Player y le asignan recursos. Aquí podemos ver la gran potencia de este interfaz ya que si lo único que queremos es añadir media a un programa basta con crear el objeto a partir de una fuente de datos y reproducir los datos multimedia, sin embargo usuarios más avanzados podrían controlar el proceso de la obtención de recursos, liberándolos cuando no sean necesarios, y, por último, programadores expertos, como veremos más adelante podrán crear los Players a medida.

En cuanto a los objetos Processor, estos son hijos de Player, por lo que lo contado anteriormente también es aplicable a esta clase de objetos. Las únicas diferencias estriban en que la función que crea el Processor es distinta (createProcessor()) y que se le añaden nuevas capacidades. Un Processor puede presentar los datos multimedia como hace el Player, pero lo que lo hace interesante es que la salida puede ser un objeto DataSource que proporciona un media stream a otros objetos, gracias a esto se puede cambiar el formato de los datos multimedia o incluso procesarlos dentro del Processor. El hecho de que se puedan modificar los datos, y para añadir más funcionalidad, hace que aumente un poco su complejidad al añadir más posibilidades en los estados del objeto, como ya veremos, y, lo más importante, permite modificar las características internas del propio proceso.

Otras clase importantes

Otras clases importantes que, aunque no son las que hacen la parte más importante del sistema son necesarias para definir o controlarlas. Estas clases son, por ejemplo Format, MediaEvent, EventListener, Controls, ProcessorModel, MediaLocator, MediaError, MediaException, Control, TimeBase, , etc. Format sirve para definir el tipo de media, existen las clases hijas AudioFormat y VideoFormat (que a su vez se divide en más) para adaptarse mejor. Estas clases tienen constantes (atributos final static) que definen los formatos más comunes. Son necesarias para definir el formato de salida de Processor, obtener el formato de un media stream, construir un ProcessorModel, etc.

MediaEvent es la clase padre de todos los eventos lanzados por los componentes JMF, como en otros casos sirven para advertirnos de pequeños errores, anunciar el fin de una actividad (muy útil para comunicar el fin de la presentación de media), comunicar el paso de un estado a otro en un objeto (necesario en Player y Processor), etc. Estos eventos siguen los patrones Java Beans establecidos permitiendo realizar fácilmente una comunicación con otros objetos del sistema (por ejemplo para cerrar la ventana de visualización de un vídeo al terminar). Para los diferentes tipos de eventos existen diferentes EventListener.

ProcessorModel es una clase capaz de definir internamente un Processor, cada uno de los tracks y tipos de datos internos, se usa para la creación de un Processor con unas características muy definidas o para analizar un Processor existente.

Del objeto MediaLocator ya se ha hablado anteriormente, define la localización de la fuente de datos y el protocolo a utilizar para obtenerlos, a diferencia de un URL, no necesita que el sistema implemente dicho protocolo para la creación del objeto.

MediaError y MediaException son los padres de todos los errores y las excepciones que los objetos JMF pueden lanzarcuando ocurre un error.

Control es una clase diseñada para controlar las características del flujo de datos de un track al procesarse, dependiendo del tipo de datos el objeto Control puede ofrecer unas u otras características, por ello esta clase se divide en herencia en otras muchas. Hay que tener cuidado y no confundir la clase Control con la clase Controls que es la definición de los dispositivos que componen un Player.

TimeBase representa la base de tiempos que tienen todos los objetos Clock (como veremos más adelante Player y Processor) la modificación de la velocidad o el momento de comienzo y final se obtiene respecto a esta base temporal. Para realizar una sincronización entre varios Player estos deben compartir sus elementos TimeBase.

\underline{RTP} Transmisión y recepción de streams por la red utilizando el protocolo RTP (Real-time Transfer Protocol). Al ser transmisión en tiempo real este protocolo se apoya en UDP y permite realizar ’unicast’ cuando se realiza transmisión punto a punto o ’multicast’ cuando se realiza una transmisión a una red de distribución. Entre los servicios ofrecidos por RTP se encuentra la identificación del tipo de datos, la ordenación y sincronización de los datos (incluso cuando se reciben de varias fuentes), proporcionan control y monitorización de la transmisión, etc. JMF permite transmisión, reproducción y almacenamiento de este tipo de datos. Para ello existen objetos SesionManager que controlan toda la sesión, existe un modelo de eventos adicional, distintos flujos de datos, nuevas clases derivadas de Format, reproductores especiales, DataSink para la transmisión, RTPSocket para la comunicación, etc.

Llegados ha este punto vemos con claridad que enviando uno los streams pro-

ducidos por un player o processor, y teniendo otra máquina virtual que lo reciba y reproduzca mediante un player o un processor se ve con claridad el protocolo RTP, pero asociado a la transmisión de datos con el protocolo RTP está el protocolo de control de esos datos RTCP que no se ve con tanta claridad, este protocolo queda implicito por los distintos eventos que son lazados a la llegada y envio de los streams. Puesto que son imprescindibles para la implemtación de cualquier aplicación se van ha explicar.

El SessionManger mantiene unh RTPstreams para cada paquete de datos RTP

en la sesion. Hay dos tipos de RTP streams:

1. ReceiveStream representa un stream que llega desde un participante remoto. (Un ReceiveStream es un evento lanzado cuando cuando se detecta la entrada de un stream nuevo).

2. SendStream representa un stream de datos que es enviado a la red. (Un SendStream es un evento lanzado cuando llamamos al método createSendStream de la clase SessionManger).

\underline{Eventos RTP}

Los eventos siguientes están definidos en el paquete javax.media.rtp.event, para

controlar estos eventos podemos implemetar varios RTP listener. Hay definidos cuatro tipos de enventos:

SessionListener. Recive notificaciones de los cambios en la sesión.

SendStreamListener. Recive notifiaciones de cambios en el estado de un stream RTP que ha comenzado a transmitirse.

ReceiveStreamEvent. Recive notificaciones de cambios en el estado de un stream RTP que ha comenzado a recibirse.

RemoteListener. Recive las notificaciones de cambios en el estado de un participante remoto.

Session Listener

Podemos implementar Session Listener para recibir notificaciones acerca de eventos de la sesion RTP, como la entrada de nuevos participantes, entendiendo como partipante la máquina remota que nos envia streams.

Hay dos tipos de eventos:

NewParticipantEvent. Indica que nuevo partipante se ha añadido a la sesion.

LocalCollisionEvent: Indica que el puerto de conexión ya esta siendo utilizado.

Send Stream Listener

Podemos implementar SendStreamListener para tener notificaciones de:

Un nuevo stream ha sido creado de forma local.

La transferencia de datos de un ’DataSource’ ha comenzado o se ha parado.

El formato del stream ha cambiado.

Hay cinco tipos de eventos asociados a SendStream

NewSendStreamEvent. Indica que un nuevo stream de envio ha sido creado

ActiveSendStreamEvent. Indica que hay transferencia de datos.

InactiveSendStreamEvent. Indica que la trasnferencia de datos esta parada. LocalPayloadChangeEvent. Indica que el formato de envio ha cambiado StreamClosedEvent. Indica que el stream ha sido cerrado.

Receive Stream Listener

Podemos implementar ReciveStreamListener para recibir notificaciones de. Un nuevo stream de recepción ha sido creado La transferencia de datos a comenzado o parado Fin de la transferencia El formato del stream de recepción ha cambiado.

Hay siete tipos de eventos asociados a ReceiveStream NewReceiveStream. Indica que le SessionManageer ha creado un nuevo stream para una transferencia. ActiveReceiveStreamEvent. Indica que la transferencia de datos ha comenzado. InactiveReceiveStream. Indica que la trasnferencia de datos se ha parado. TimeoutEvent. Indica que el la transferencia de datos tiene fin. RemotePayloadChageEvent. Indica que el formato de envio ha cambiado. StreamMappedEvent. Indica que un stream que no tenia remitente ha sido asociado a uno. ApplicationEvent indica que un RTCP APP (RTCP modificado para la apliación) ha sido recivido

RemoteListener

Se puede implementar RemoteListener para recivir eventos de notificación o mensages de control RTP, desde los participantes remotos. Esto nos permite recibir RTPC mensages de control. Hay tres eventos asociados.

ReceiveReportEvent. Indica que ha llegado una notificación de envio. SenderReportEvent. Indica que una notificación de envio ha sido mandada. RemoteCollisionEvent. Indica que el puerto por el que intentamos acceder esta ocupado.

A.4. Abstract Window Toolkit (AWT)

El desarrollo de applets de Java y de aplicaciones gráficas requiere trabajar con

AWT, este paquete (incluido en el JDK) proporciona componentes básicos de interfaz, como botones, listas, menús, etiquetas etc …

A.4.1. Descripción de AWT

Los componentes AWT son idependientes de las plataforma, y son usados pri-

mordialemnte para construir interfaces gráficas de usuario. Además, AWT proporciona también un mecanismo de manejo de enventos, soporte para transferencia de datos y manipulación de imagenes. AWT incluye también paquetes para manipulación avanzada de fuentes, impresión, accesibilidad geométrica y métodos de entrada.

A.5. Contenido del CD

Aplicación

• Servidor

• Cliente

• Media Archivos utilizados para hacer las pruebas

JDK utilizado

JMF utilizado

Docuementación Utilizada

Ejemplo de Player

Índice de figuras

2.1. Video y Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.2. Configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3. Actualizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4. Archivos Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10