lunes, 8 de febrero de 2010

Aplicaciones sobre SCTP (Stream Control Transmission Protocol). Streaming de video mediante JMF (Java Media Framework)


Hi,

before to start writing I have to say that the next information could be interesting for lot of people but I'm going to write in spanish because my programs were written in spanish and, now, I don't have enough time to translate them. But don't worry, if somebody needs to contact me and says me that is important for he/she to understand my programs I promise help him/her in all possible.

In summary, I'm going to introduce some aspects of this protocol and then I will write a brief explanation of each of my programs: one basic client/server application written in C, one basic client/server application written in Java and, finally, one client/server application written in Java and using JMF (Java Media Framework) that lets build a real-time video streaming scenario.
-----------------------------------------------------------------------------------
Comienzo con la entrada en sí.

En resumen, voy a introducir algunos aspectos de este protocolo y, después, una breve explicación de cada uno de mis programas: una aplicación básica cliente/servidor escrita en C, una aplicación básica cliente/servidor escrita en Java y una aplicación cliente/servidor escrita en Java y usando JMF (Java Media Framework) que permite construir un escenario de streaming de video en tiempo real.

INTRODUCCIÓN:
SCTP o protocolo de control de transmisión de flujo, es un protocolo de nivel de transporte orientado a conexión que, a diferencia de TCP y su concepto de conexión, introduce una nueva forma de comunicación entre sistemas denominada asociación.

Las principales características de SCTP son las siguientes:
  • Es un protocolo punto a punto. Se establece el intercambio de datos entre dos extremos conocidos. 
  • Proporciona transporte fiable de datos de usuario, detectando y reparando los datos erróneos o fuera de secuencia. 
  • Se adapta a la tasa de transferencia, disminuyendo la velocidad de envío de datos en caso de congestión en la red. 
  • Multi-homing. Permite establecer asociaciones robustas entre dos extremos cada uno de los cuales puede ser alcanzado mediante más de una dirección de red. Hacia cada una de ellas se encaminan los mensajes de forma independiente de manera que, si una de las interfaces de red queda fuera de servicio, la comunicación no se ve afectada ya que el flujo de datos se redirige por una de las otras, si las hay. 
  • Cada asociación puede contener uno o mas streams que permiten el envío de datos de forma independiente entre cada uno de ellos.
Para información mas detallada, esta es la página principal desde la que se puede acceder a la RFC de SCTP, el API de sockets, etc.

Las aplicaciones ha sido probadas sobre dos máquinas virtuales creadas con VMware Server y con sistema operativo SuSE Linux 10.3. Es necesario instalar el paquete lksctp para que el SO soporte este protocolo. El hecho de haber utilizado máquinas virtuales es debido a la gran facilidad que ofrecen para crear interfaces de red, ya que va a ser necesario utilizar al menos dos interfaces de red en al menos un extremo para probar la capacidad de multihoming que ofrece SCTP.

CLIENTE/SERVIDOR EN C
La aplicación es sencilla de utilizar y nos ofrece la posibilidad de utilizar una importante funcionalidad que ofrece SCTP como novedad frente a TCP o UDP, es decir, el alta y baja de direcciones IP dentro de una asociación durante la interacción entre el cliente y el servidor y el establecimiento de la dirección primaria utilizada en cada extremo para transmitir la información.

El cliente de esta aplicación se encuentra en el fichero cliente_one.c ya que implementa sockets de tipo one_to_one. Este cliente mostrará un menú al usuario de forma que éste pueda realizar las tareas necesarias. Es el que se encarga de mandar las operaciones al servidor. 
Para compilar y ejecutar dicho fichero se deberán introducir los siguientes comandos en el terminal:
  • Compilar: gcc -Wall -o cliente cliente_one.c -lsctp -L/usr/local/lib
  • Ejecutar: ./cliente
Al ejecutarlo pedirá al usuario la/s dirección/es y puerto del servidor a los que desea conectarse, así como la/s dirección/es y puerto desde los que desea realizar la asociación. Después de realizarse la conexión se mostrarán ciertos parámetros asociados a ella y el menú principal de opciones, a través de las cuales el usuario interactuará con la aplicación.

El servidor se encuentra en el fichero servidor_one.c  implementando sockets de tipo one_to_one. Su funcionalidad se limita al tratamiento de los mensajes que le llegan del cliente, mostrando por pantalla cada
evento producido y los cambios en su configuración.
Para compilar y ejecutar la aplicación servidor se deberán introducir los siguientes comandos en el terminal:
  • Compilar: gcc -Wall -o servidor servidor_one.c -lsctp -L/usr/local/lib
  • Ejecutar: ./servidor
Una vez ejecutado el servidor, pedirá al usuario la/s dirección/es y puerto desde los que escuchara el proceso servidor y tras ello funcionará de forma automática mostrando únicamente los distintos eventos y sucesos producidos durante su funcionamiento.

Los programas se pueden descargar desde aquí:  cliente , servidor y headers

Btn_blue_77x28

 CLIENTE/SERVIDOR EN JAVA
 Para realizar esta aplicación se ha utilizado un API de sockets al que se puede acceder desde aquí. Este API no se encuentra completo por lo que hay parte de funcionalidad de SCTP que no se podrá probar con esta aplicación, pero ha sido importante familiarizarse con esta parte para poder realizar la aplicación de streaming de vide, ya que está escrita en Java y utiliza este API. Creo que Sun Microsystems está creando un API mas completo para el que desee pegarse un poco con él.


El cliente se encuentra implementado en el fichero ClienteOne.java. El nombre se debe a que el tipo de socket utilizado es de tipo one-to-one.
  • Compilación: javac ClienteOne.java
  • Ejecución: java -cp . -Djava.library.path=. -Xcheck:jni ClienteOne
La opción -cp permite indicar el classpath o directorio donde se encuentranlas clases java, -Djava.library.path indicará el directorio donde se encuentran los binarios y -Xcheck:jni efectúa comprobaciones adicionales de funciones JNI (Java Native Interface).


El servidor se ha desarrollado en el fichero ServidorOne.java.
  • Compilación: javac ServidorOne.java
  • Ejecución: java -cp . -Djava.library.path=. -Xcheck:jni ServidorOne
Los programas se pueden descargar desde aquí: cliente y servidor
 
Btn_blue_77x28


STREAMING DE VIDEO MEDIANTE SCTP/JMF
Las dos aplicaciones anteriores nos sirven para tener una primera toma de contacto con el uso de las funciones que permiten utilizar las características del protocolo SCTP. Nuestro objetivo ahora, es utilizar estos conocimientos para realizar streaming de video sobre SCTP, para lo cual podemos utilizar JMF. Java Media Framework es un API que proporciona herramientas para la captura, procesamiento, almacenamiento y reproducción de datos multimedia.


¿Por qué utilizar SCTP como protocolo de transporte para el intercambio de datos en tiempo real? La razón que más me interesa destacar es que permite tener uno o más interfaces de red que se pueden utilizar como backup para que no haya cortes en la transmisión en caso de caída de los interfaces principales.


¿Por qué utilizar JMF para crear una aplicación cliente/servidor multimedia? JMF ofrece todo lo necesario para implementar una aplicación multimedia y, además, nos permite sustituir el protocolo de transporte utilizado. En este caso, se ha utilizado SCTP en vez de TCP o UDP.

He conseguido realizar una aplicación cliente/servidor mediante el API que ofrece Java Media Framework que utiliza RTP para realizar el streaming de datos, RTCP para llevar la información de control del flujo RTP y SCTP como nivel de transporte. Al menos de momento, no puedo colgar esta aplicación porque tengo la intención de utilizarla para construir un sistema de videovigilancia mediante cámaras IP.


En cualquier caso, no es demasiado costoso hacer una aplicación de este tipo, pero hay que tener siempre presente y muy claro el orden en la pila de protocolos para todos los pasos que hay que realizar. Daré una serie de pautas que espero os sirvan para crear vuestra aplicación.


Arquitectura y funcionamiento
El concepto de modelo de procesamiento de datos que sigue JMF es bastante sencillo de comprender. Como muestra la primera figura, consiste básicamente en una entrada de datos, que puede provenir de un dispositivo capturador de voz, como un micrófono; un fichero de datos, por ejemplo un videoclip de música almacenado en nuestro PC o directamente de la red, de un servidor de streaming de video, por ejemplo.
 

Una vez se tiene el input instanciado, se llevará a cabo un procesamiento del mismo. Este punto puede ser más o menos problemático o complejo dependiendo de las necesidades de la aplicación que se esté realizando y de las peculiaridades de la entrada y salida que se quiera gestionar/ofrecer.
 

Por último, los datos podrán ser presentados por pantalla mediante un interfaz gráfico, almacenados en un fichero o enviados a través de la red. El modelo fundamental es el siguiente:




Para llevar a cabo cada uno de los apartados que presenta este esquema, el API ofrece una serie de clases e interfaces que permiten al programador realizar una aplicación a medida, respondiendo a sus necesidades.
 

El modelo se puede repetir en el conjunto de nuestra aplicación, ya que, por ejemplo, se puede realizar un servidor que capture los datos de entrada de un micrófono, los procese y envíe a través de la red hacia un cliente que capture dicha información, realice su procesamiento y la muestre mediante un reproductor con sus correspondientes controles. En este caso, la comunicación entre cliente y servidor se realizaría mediante
RTP (Real-Time Transport Protocol) atendiendo a la estructura siguiente:






Se recomienda leer el API Guide accesible desde aquí ya que contiene toda la información necesaria acerca de JMF y múltiples ejemplos que ayudarán al lector a comprender mucho mejor lo leido.



Clases e interfaces
En este apartado se explicarán las clases e interfaces principales que ofrece JMF para tratar cada una de las partes diferenciadas en el primer esquema. El API de JMF 2.0 se puede ver aquí.


1) Entrada
Como ya se ha introducido, JMF permite capturar datos de fuentes distintas de información, por lo que, dependiendo de cada una de ellas, se deberán utilizar unas clases u otras del API.



Si el origen de estos datos es un micrófono o una cámara de video, se deberá utilizar primero la clase CaptureDeviceManager que ofrece métodos para gestionar los dispositivos del sistema utilizando mecanismos de registro y petición para localizar dichos dispositivos devolviendo objetos CaptureDeviceInfo para los que estén disponibles. El interfaz relacionado se llama DeviceManager.

CaptureDeviceInfo devideInfo = CaptureDeviceManager.getDevice(“deviceName”);
MediaLocator loc = deviceInfo.getLocator();


La clase CaptureDeviceInfo contiene un método getLocator que permite obtener un MediaLocator. Una vez obtenido el locator para este caso, los tres orígenes de datos se tratan del mismo modo. En los dos casos restantes, desde fichero y desde la red, el MediaLocator se puede construir directamente, indicando la ruta absoluta a dicho fichero, en el primer caso, o la URL, en el segundo.


MediaLocator loc = new MediaLocator(“file:///v.mpg”);
MediaLocator loc = new MediaLocator(“http://ip/v.mpg”);
 

La finalidad de haber obtenido el locator es poder crear un objeto de la clase DataSource que, como su propio nombre indica, será el origen de datos para la aplicación, ya que las clases de gestión, procesamiento y reproducción pueden tratar con este objeto directamente.

DataSource source = new DataSource(loc);
 

2) Procesamiento
Hay muchos elementos a tener en cuenta en esta parte y, dependiendo de qué tipo de aplicación se desee realizar, se utilizarán unos u otros, de forma que en este apartado no se podrá explicar de forma lineal respecto a la forma de programar. Una enumeración de las clases/interfaces mas utilizados en la “capa” de procesamiento serían Manager, Format, TrackControl, RTPManager y Processor.
 

La clase Manager se utiliza básicamente para crear objetos de las clases principales, es decir, DataSource, DataSink, Processor y Player, mediante sus métodos estáticos create.

DataSource dso = Manager.createDataSource(loc);
DataSink dsi = Manager.createDataSink(dso, locDest);
Processor pr = Manager.createProcessor(dso);
Player pl = Manager.createPlayer(dso);
 

La clase Format y, más en concreto, sus subclases AudioFormat y VideoFormat permiten gestionar el formato en que la información multimedia será procesada. El interfaz TrackControl permite establecer el formato de cada uno de los tracks que conformen el DataSource con el que se está trabajando. Para ello utiliza el método setFormat al que se le pasará una instancia de AudioFormat o VideoFormat con el
formato adecuado.



La clase abstracta RTPManager es el punto de partida para crear, gestionar y cerrar sesiones RTP. Se utilizará para crear las sesiones RTP (initialize) y los streams de salida (createSendStream), así como los listeners correspondientes para gestionar tanto streams como sesiones (addSendStreamListener, addSessionListener), añadir los destinos de la transmisión (addTarget) y finalizar todos los recursos utilizados durante el transcurso de la sesión (dispose).

RTPManager rtpManager = RTPManager.newInstance();
rtpManager.initialize(localAddress);
rtpManager.addTarget(remoteAddress);
rtpManager.createSendStream( dso, 1);
rtpManager.dispose();
 

El interfaz Processor, aunque extiende el interfaz Player que procesa los datos como una caja negra y sólo los envía a los destinos preseleccionados (motivo por el cual no se encuentra en esta sección), soporta un interfaz programable que permite habilitar el control sobre el procesamiento de los datos y el acceso a los streams de salida. El uso común de un Processor es el siguiente:
· demultiplexar el stream multimedia en tracks separados: el método getTrackControls devuelve un array de objetos TrackControl.
· transcodificar estos tracks pasándolos de un formato a otro: método setFormat sobre cada objeto del array.
· multiplexar los tracks separados para formar un stream entrelazado de un tipo de contenido particular: setContentDescriptor.


TrackControl [] tracks = processor.getTrackControls();
tracks[i].setFormat(new VideoFormat(VideoFormat.MPEG_RTP));
ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
processor.setContentDescriptor(cd);





El Processor tiene un ciclo de vida que habrá que tener en cuenta a la hora de llamar a sus métodos ya que, dependiendo del estado en que se encuentre, se podrán invocar unos u otros.




Cuando se llama al método configure del Processor, éste pasa a estado “Configuring” en el que se conecta al DataSource, demultiplexa el stream de entrada y accede a la información sobre el formato de los datos. Pasará a estado “Configured” cuando se ha realizado la conexión al DataSource y se ha determinado el formato de los datos. En tal caso, será enviado el evento ConfigureCompleteEvent. Tras llamar al método realize de Processor pasará a estado “Realized” en el que se considerará totalmente construido.

3) Salida
De la misma forma que sucede con la entrada de datos, la salida también se puede realizar de distintas formas: se puede presentar mediante un reproductor multimedia utilizando el interfaz Player, se puede almacenar en un fichero mediante la clase DataSource o se puede enviar a través de la red utilizando DataSink o RTPManager.
 

JMF posee un interfaz denominado Player que, como su propio nombre indica, permite realizar un reproductor multimedia ya que ofrece métodos para obtener componentes AWT, controles para el procesamiento de los datos y formas de gestionar otros Controllers.

class PlayerPanel extends Panel {
   Component vc, cc;
   PlayerPanel() {
      Player p = Manager.createPlayer(dso);
     setLayout(new BorderLayout());
     vc = p.getVisualComponent();
     add("Center", vc);
     cc = p.getControlPanelComponent();
     add("South", cc);
   }
}





Al igual que sucede con el Processor, el Player también tiene un ciclo de vida que hay que respetar.




Cuando creamos una instancia de un Player, éste se encuentra en estado “Unrealized”. La llamada a su método realize pone al Player en estado “Realizing”, en el cual, se determinan los requerimientos de los recursos necesarios para operar. Al terminar esta fase, se pasa al estado “Realized” en el que el Player conoce los recursos necesarios que necesita y la información sobre el tipo de información que va a
presentar. Por ello, en este momento puede ofrecer componentes visuales y de control. El siguiente paso es llamar al método prefetch, de forma que se alcanza el estado “Prefetching” en el que el Player está preparándose para presentar la información multimedia, precargando los datos, obteniendo recursos de uso exclusivo y haciendo lo que necesite para prepararse para reproducir. Al finalizar quedará en estado “Prefetched” en el que ya se puede llamar al método start para iniciar la reproducción. La llamada a este método pondrá al Player en estado “Started”. 


Dentro de la aplicación, el programador puede ir capturando los eventos de transición entre estados enviados por el Player. El interfaz ControllerListener ofrece una forma hacerlo mediante la implementación de su método controllerUpdate dentro del cual se puede ir diferenciando entre los distintos eventos del interfaz Controller realizando el tratamiento adecuado según el caso.

La segunda opción de tratamiento de datos a la salida y la más sencilla, es el almacenamiento de datos en un fichero de destino. Tras utilizar un Processor para realizar algún tipo de procesamiento sobre el DataSource de entrada, se puede obtener el DataSource de salida que será almacenado en un fichero de la siguiente forma:



DataSource dataOutput = processor.getDataOutput();
MediaLocator dest = new MediaLocator(“file:///out.mpg”);
DataSink sink = Manager.createDataSink(dataOutput, dest);
sink.open();
sink.start();
 

Por último, se pueden enviar datos a través de la red mediante RTP de dos formas:
· Utilizando un MediaLocator que contendrá los parámetros de una sesión RTP para construir un DataSink.
· Utilizando un RTPManager para crear streams de salida y controlar la transmisión.
 

Si se utiliza la primera opción sólo se podrá transmitir el primer stream del DataSource, por lo que, si se desea realizar una aplicación más compleja en la que se necesiten recibir múltiples streams, monitorizar las estadísticas de la sesión o realizar cierto tipo de procesamiento basado en la recepción de eventos, se debe utilizar RTPManager.

El interfaz DataSink permite leer datos de un DataSource y enviarlos hacia algún destino que será especificado mediante un MediaLocator. Estas instancias serán indicadas como parámetros para construir el DataSink:
 

String url = “rtp://124.124.2.4:4242/audio/1”;
MediaLocator locDest = new MediaLocator(url);
DataSink dsi = Manager.createDataSink(dso, locDest);
 

Como se indicó en el apartado de procesamiento, la clase RTPManager es el núcleo para realizar aplicaciones RTP complejas. Esta clase ofrece dos formas de establecer sesiones RTP para la transmisión de datos multimedia:
· Utilizando los métodos addTarget y removeTarget, de forma que el nivel de transporte es UDP. 

· Utilizar una clase que implemente el interfaz RTPConnector en la que el programador implemente el nivel de transporte que desee.

Para usar una u otra forma, RTPManager posee tres métodos initialize, dos para el primer caso y uno para el segundo. Por otra parte, siempre que el nivel de transporte sea UDP, las transmisiones podrán ser multicast además de unicast.


RTPConnector es un interfaz que implementa la capa de transporte subyacente bajo RTP. El programador deberá realizar una clase que implemente esta interfaz para ser utilizada por RTPManager realizando la gestión de la recepción de paquetes de datos (RTP) y de control (RTCP- Real Time Control Protocol).
 

RTPManager rtpManager = RTPManager.newInstance();
int port = 20000;

//Se crea una instancia de la clase que implementa el interfaz RTPConnector. 
//En este caso la capa de transporte es SCTP, por lo que primero se debe establecer la asociación
RTPSocketHandler handler = new RTPSocketHandler(port);
handler.listenSocket();
handler.connectSocket(“127.0.0.1”, port);
//Inicializa RTPManager
rtpMgrs[i].initialize(handler);
SendStream sendStream = rtpManager.createSendStream(dso, 1);
sendStream.start();




Esta es una captura de los players generados por mi aplicación: 

 



Desde estas ventanas se puede controlar el video y audio, así como ver las características del flujo de datos que es está recibiendo y el desempaquetado que se está llevando a cabo.

En la parte del servidor he hecho que se mostrará la siguiente ventana que mostrará la información de los tracks contenidos en el fichero multimedia y un botón close para terminar la transmisión cuando se desee.


Un saludo.
 



30 comentarios:

  1. Hola Jorge.
    Mi nombre es Carlos Inostroza y me encuentro trabajando con SCTP. Espero que esta sea la via correcta para hacerte una consulta con respecto a este protocolo.
    No soy un experto en la programación pero decidí trabajar con SCTP ya que me interesa el área de redes. Estoy desarrollando un programa cliente-servidor que me permite enviar cualquier tipo de archivo. Cada stream tiene un payload de 1452 bytes (verifique la limitación con el wireshark). El problema que tengo es cuando el archivo es muy grande y el numero de stream supera cierto valor, en mi caso el son 45884. El lado que recibe los datos se detiene unos 10 segundos lo que obviamente me genera perdidas.

    Muchas gracias por tu tiempo y de verdad espero me puedas ayudar.

    ResponderEliminar
  2. Hola Carlos,

    más que una restricción de SCTP yo diría que es de otra cosa.

    Esto está sacado de la RFC:
    - Stream Identifier S: 16 bits (unsigned integer)

    Identifies the stream to which the following user data belongs.

    - Stream Sequence Number n: 16 bits (unsigned integer)

    This value represents the stream sequence number of the following user data within the stream S. Valid range is 0 to 65535.

    When a user message is fragmented by SCTP for transport, the same stream sequence number MUST be carried in each of the fragments of the message.

    Tus 45884 streams creados por este envío de datos ni siquiera alcanzan el rango de identificadores de SCTP, además, no debería ocurrir que cada stream lleve un identificador distinto, ya que SCTP está fragmentando por MTU=1500 en tu red y cada fragmento debería llevar el mismo SSN.

    Si me explicas un poco lo que estás intentando hacer quizá pueda ayudarte mejor.
    - Protocolo que utilizas por encima de SCTP para hacer la transferencia --> quizá sea el causante del problema.
    - Si haces algún bucle en el programa para enviar cada stream.
    - Con que estas programando. ¿Utilizas JMF?
    - ¿Qué envias entre cliente y servidor? Un único fichero o varios y de cuantos MB.

    En cualquier caso, se me ocurre una cosa que es lo que yo haría para buscar el problema.
    Ejecuta tu aplicación con el wireshark corriendo tanto en el cliente como en el servidor si usas dos máquinas, si no será un solo wireshark. E identifica donde se produce el corte de 10 segundos e intenta averiguar que ha pasado exactamente.

    Un saludo.

    ResponderEliminar
  3. Primero que todo muchas gracias por responder. Me ha costado un poco profundizar en el protocolo debido a la poco información detallada que existe. Tu trabajo me ha sido de mucha ayuda en ese sentido.

    Ahora te cuento un poco mas sobre lo que estoy haciendo. Me encuentro programando en lenguaje C, en equipos con Ubuntu con el kernel 2.6.31-28. La operación cliente-servidor es la siguiente:

    - el servidor queda a la escucha de alguna petición
    - el cliente envia un pequeño mensaje para iniciar la asociación
    - se recibe el mensaje en el servidor. A continuación éste llama a una función que envía al cliente un mensaje con el número de streams que son necesarios para enviar el archivo de acuerdo a su tamaño
    - el cliente recibe esta última información
    - entonces, el servidor realiza una llamada a otra función que es la encargada de enviar el archivo: un ciclo while se ejecuta hasta que se llega al final del archivo (while(!feof(nombre_puntero))); se utilizan funciones de lectura de archivos (ftell, fread), y se envian los streams usando de la siguiente forma la funcion:

    sctp_sendmsg(sock,buffer,sizeof(buffer),struct, struct_size,0,0,i,0,0)
    (he cambiado los nombres de las variables para tu comprensión, en verdad no habia mucha diferencia), el buffer es de 1452 bytes y al final de esta función aumento el valor de "i" en uno

    - el cliente también entra en un ciclo while (while (i < streams)); al final del ciclo se aumenta el valor de "i" hasta alcanzar el numero de streams. La forma en que determino cada streams es la siguiente:
    if(BytesReceived == 1452) {
    if (SndRcvInfo.sinfo_stream == i) {
    y escribo inmediatamente el archivo usando fwrite (previo posicionamiento en el archivo usando fseek).

    El valor de 45884 que te mencione corresponde a "sinit_max_instreams" y va cambiando cada vez que trato de enviar un archivo de distinto tamaño. Se me olvido mencionar que cuando el receptor se detiene aproximadamente por 10 segundos después sigue recibiendo datos y se va deteniendo cada 45884 streams (este valor se dio con un archivo de 698MB).

    Estoy enviando un único archivo, he trabajado con pdf, jpg, mp3, avi, y con archivos de hasta 90MB (cuando el numero de streams, de payload de 1452 bytes, no sobrepasa los 65635) ningún problema.

    Nuevamente gracias y cualquier sugerencia te la agradeceré.

    Saludos

    ResponderEliminar
  4. Hola Carlos,

    parece que tu planteamiento está bien, aunque según la teoría de SCTP el valor de "sinit_max_instrems" no debería ser tan alto para transmitir un solo fichero, un mismo fichero debería transmitirse con un mismo ID de stream, aunque se creen muchos fragmentos todos ellos deberían ir por el mismo stream. Si lo que estás probando es la capacidad de paralelizar el flujo en distintos streams bien, si no, intenta no crear nuevos streams. He mirado capturas de wireshark de mis pruebas y el SID es siempre cero, el que aumenta es SSN. En cualquier caso, yo no hice pruebas con este parámetro por lo que tampoco te puedo decir exactamente cuál es su buen uso, lo dejé por defecto al transmitir video.

    Mis pruebas iban enfocadas a probar la capacidad de multihoming de SCTP, con dos interfaces en un extremo podía tirar una de ellas mientras estaba transmitiendo el video sin que se produjese interrupción en el flujo de datos. Para ello, me fueron muy útiles estos tres parámetros. Échales un vistazo a ver si te sirven de algo. A mi me solucionaron un retardo que se producía al bajar la interfaz primaria en la asociación, por la que se estaba transmitiendo el video. Aquí tienes los valores por defecto y los que yo puse.

    net.sctp.rto_max = 60000 (sustituido por 130)
    net.sctp.rto_initial = 3000 (sustituido por 120)
    net.sctp.rto_min = 1000 (sustituido por 110)

    Siento darte solo algunas ideas, pero hace bastante tiempo que dejé de trabajar con SCTP y ni siquiera tengo el entorno de pruebas montado.

    ResponderEliminar
  5. Muchas Gracias por tus comentarios y tiempo!!! Revisaré con más detalle esos parámetros.... espero escribirte nuevamente con el problema ya solucionado.

    Gracias :)

    ResponderEliminar
  6. Jorge, ya solucioné el problema despues de un breve receso y un par de vueltas!! Era tan simple pero a la vez muy difícil de ver.... tuve que cambiar el valor "i" en
    sctp_sendmsg(sock,buffer,sizeof(buffer),struct, struct_size,0,0,i,0,0)

    por sri.sinfo_stream (con su estructura correspondiente) y asi se soluciono todo. Muchas gracias por tu ayuda.

    ResponderEliminar
  7. Estos trabajos de investigación muchas veces nos saturan la mente y es mejor, como dices, tomarse un receso porque luego está todo más claro, jeje. Me alegro de que lo hayas solucionado. Tu esfuerzo ha tenido su recompensa.

    ResponderEliminar
  8. Angeles Telemattica27 de febrero de 2011, 2:37

    Hola estoy por realizar una exposicion sobre sctp y la materia es seguridad en redes, me gustaria enfocar la exposicion a los efectos de este protocolo en seguridad pero no se consigue material en la web,sinceramente busco la manera de hacer interezante mi intervencion y ver las ventajas de este protocolo sobre el tcp y udp con un ejemplo practica, vi en you tube un video muy corto de multihosting en ns2, y otros pocos videos que puedo aprovechar para la exposicion, pero que me recomiendas,

    Te agradezco mucho el aporte que puedas darme

    ResponderEliminar
  9. Te diré lo que hice en mi presentación del proyecto fin de carrera "Aplicaciones sobre SCTP", por si te ayuda en algo.
    Terminé realizando streaming de video mediante SCTP simulando la caida del interfaz primario en el cliente de forma que se podía ver como el video continuaba ya que el streaming de datos se pasaba a realizar por el interfaz secundario.
    Es la parte de JMF que ves en el blog y, además de verse por el Player que cree, dejé corriendo dos wireshark, uno en cliente y otro en servidor para que el tribunal viera que no se había realizado otra conexión como hubiera ocurrido con TCP y UDP.
    Lo que no se es si dispones de algún tipo de aplicación SCTP, si la tienes, aunque no transmita video ni tenga un interfaz bonito, etc. puedes enviarte un fichero grande entre cliente y servidor, cortar un interfaz y enseñar lo que pasa en wireshark.
    No tengo video de mi presentación, pero si quieres puedes utilizar mi aplicación Java, aunque no es rápido montar el entorno si no lo has hecho nunca.
    Ahora que terminaba de escribirte se me ha ocurrido una idea bastante simple que puedes llegar a hacerla tan vistosa como quieras.
    Es lo que hice yo para explicar multihoming. Mediante transparencias powerpoint explicas la asociación, streaming de video, caida del interfaz, por qué en SCTP no pasa nada y qué pasaría en TCP y UDP y finalización de la asociación. Con cajas, paquetitos, etc. puede quedar bien.

    Espero que te sirva...

    Un saludo.

    ResponderEliminar
  10. Gracias por contestar Jorge...
    Mi profesion es electricidad mencion telecomunicaciones y estoy haciendo este posgrado en redes para contar con otras herramientas, te digo esto porque el manejo de java es desconocido para mi, pero en maquinas virtuales y opensuse 11.1 he tenido mas contacto.. tengo el virtualizador virtualbox version 3.2.12, cuando hablas de que probaste la aplicacion en dos maquinas virtuales, a ambas se les instala opensuse o solo a una? no me queda claro.. para instalar el paquete lksctp, supongo que lo bajo de internet?.. los ficheros que hiciste (cliente y servidor).. de que forma los almaceno en las maquinas virtuales?.. disculpa tantas interrogantes, pero este es todo un mundo nuevo para mi persona y me parece interezante, si puedes orientarme mejor, ahora conociendo el nivel de conocimiento que tengo del area, te lo agradeceria una vez mas!

    ResponderEliminar
  11. Yo cree las máquinas vituales con VMware client y en ambas instale SuSE 10.3, con el paquete lksctp que puedes descargar de internet. La aplicación Java que crea players y hace streaming de video entre cliente y servidor no está colgada, como se indica en la entrada del blog, por lo que tendrías que crearte una para lo cual ofrezco en el blog algunas pautas que pueden ser de gran ayuda. En cualquier caso, si solo tienes que hacer una presentación, no te recomiendo perder tanto tiempo en crear una aplicación ya que no hay mucha documentación en Internet sobre como hacerlo con SCTP y no es del todo sencillo.

    ResponderEliminar
  12. Hola, estoy tratando de implementar un servicio de almacenamiento multimedia en Cloud, con el que pueda almacenar lo que grabo con mi webCam en la red. Ahora bien, para realizar la transmisión de vídeo al servidor en el que quiero almacenarlo me gustaría conocer los parámetros de la red, para poder adaptar la transmisión a los mismos. Al leer tu entrada del blog, me he dado cuenta de que es posible que el protocolo SCTP me ayude a lograrlo, sabes como realiza este protocolo la adaptacion de la tasa de envio a las condiciones de la red?

    Por otra parte, he intentado usar el JMF para capturar un flujo rtp, y no he sido capaz de hacerlo funcionar ni una sola vez. Uso Java sobre Linux.

    Un saludo y gracias por compartir vuestros conocimientos

    ResponderEliminar
  13. Hola, lo primero es que, si no necesitas utilizar ciertas características de SCTP como es la posibilidad de realizar conexiones entre múltiples interfaces contra múltiples interfaces, es mejor que uses TCP o UDP ya que los ejemplos que vienen en el API guide están hechos con estos protocolos. Meterle como capa de transporte SCTP solo te complicaría la vida, en mi humilde opinión, claro.
    Sobre la siguiente pregunta, ¿cómo realiza la adaptación de la tasa de envío?, quizá no te haya entendido bien, pero los protocolos de nivel 4 no se encargan de esas cosas, sería el protocolo de nivel 5 (Stack TCP/IP) el que te hace eso, por ejemplo, RTP o RTSP. Son los que tienen distintos buffers de envio y recepcion, gestión de retardos, etc. Si no lo has hecho ya, te aconsejo que asimiles el API guide de JMF y copies y pegues los ejemplos que vienen y te vayas haciendo una aplicación sencilla y que funcione, más compleja cada vez hasta que consigas lo que quieres. Prueba a recoger el video de un fichero y guardarlo en otro fichero, por ejemplo, en tu mismo PC, nada de servidor en principio. Poco a poco.

    Espero haber aportado algo...
    Un saludo!

    ResponderEliminar
  14. Lo primero, gracias por responder tan rápido, la verdad es que no me lo esperaba. Me había parecido útil utilizar SCTP porque en la descripción que pones arriba dice que:

    "# Se adapta a la tasa de transferencia, disminuyendo la velocidad de envío de datos en caso de congestión en la red. "

    Y eso es justo lo que yo quiero que haga lo que yo estoy haciendo, pero haré caso de tu consejo porque seguro que sabes mucho más de este protocolo que yo.

    Muchas gracias,
    Un saludo

    ResponderEliminar
  15. Vale, no te entendí bien, pensaba que te referías al flujo de datos en si, al video en este caso. Es cierto que tanto SCTP como TCP tienen mecanismos de control de flujo y congestión, algo distintos, pero que hacen lo mismo. La verdad es que yo utilicé SCTP mas como UDP que como TCP (tiene características similares a ambos según como lo utilices) ya que necesitaba realizar un servidor de streaming y en ese caso es prioritario que los datos lleguen cuanto antes, con el menor overhead posible y sin importar si se pierde algún paquete, ya que no quieres que un trozo de video se reproduzca mas tarde. En tu caso, que es depositar un video capturado por webcam en un servidor, como dices, es interesante utilizar un protocolo fiable para asegurarte que llega todo. Por tanto, yo utilizaría TCP sin duda. Si lo haces funcionar, puedes sustituirlo después por SCTP sin demasiados problemas, pero no creo que te queden ganas, jeje. No me enrollo mas.
    Saludos!

    ResponderEliminar
  16. hola estoy creando una aplicacion de streamin y lo que hago es captuar video y audio utilizo un vector lo capturo i lo guardo como .avi quisera saber si podrias pasarme el codigo de tu aplicacion de trnasmision de video para ver como es que tengo que hacer para recibir el sreamin porque en eso estoy y no lo púedo hacer muchas grasias......

    ResponderEliminar
  17. Mi aplicación utiliza JMF, como expongo en el blog, donde doy las pautas para realizar captura de datos multimedia, envío y reproducción o almacenamiento de los mismos. Hacer una aplicación sencilla no es tan difícil, por lo que te animo a que lo hagas. Como dije, de momento no voy a colgar el código de esa aplicación.
    Un saludo.

    ResponderEliminar
  18. Hi, what do you want to know about them?
    Jorge.

    ResponderEliminar
  19. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  20. hi,
    I was trying to reach you for a long time, i'm programming for my master degree the same app that you did in your project. i met many problems while integrating sctp in jmf-rtp streaming transmission
    please can you help me out
    here my e-mail : dalel16dz[a]hotmail.fr
    best wishes
    Amina

    ResponderEliminar
  21. Hi

    your application use sctp multistreaming ?? so any chance to use it ??

    another question, I buil the program, but when executing I have this error, how i can resolve it

    Exception in thread "main" java.lang.UnsatisfiedLinkError: no dk_i1_sctp in java.library.path

    i am using ubuntu with jdk6 and dk_i1_sctp is installed, maybe you have another instruction to install this library ??

    ResponderEliminar
  22. I made a develop only in order to test the multihoming feature that SCTP provides. I really not know if my application permits the multistreaming use but I think it should although I can't ensure it.

    About your last question...I used SuSE 10.3 but it should not be important if you have installed the correct packages. The steps I followed to have my environment ready for java use were the next: (excuse me but they are in spanish. I hope you can translate it with a translator)

    1) Acceder a la página especificada más arriba y descargar los archivos
    javaSCTP-x-y-z.jar, javaSCTP-x-y-z-src.tar.gz. y javaSCTP-x-y-zdoc.
    tar.gz. que vienen en ella.

    2) Colocarlos en el /bin del directorio home a menos que se quiera
    establecer otro directorio. Bastará con incluir la ruta en la variable
    PATH.

    3) Descomprimimos el src.tar.gz. obteniendo varios ficheros y un directorio
    donde se encuentran los ficheros fuente de java. En el Makefile
    deberemos modificar la línea 11 y añadir la referencia al path donde se
    encuentra nuestro Java SDK. En nuestro caso:
    -I/usr/lib/jvm/java-1.5.0-sun-1.5.0_update13
    /include

    4) Ha sido necesario incluir la ruta al fichero jni_md.h que tenemos en:
    /usr/lib/jvm/java-1.5.0-sun-1.5.0_update13
    /include/linux/jni_md.h
    para que desde el jni.h encuentre este fichero. También se podría haber
    modificado el jni.h cambiando el include de jni_md.h a linux/jni.h.

    5) Dependiendo de la versión del lksctp utilizado quizá debamos comentar
    las líneas 38 a 61 del fichero dk_i1_sctp_SCTPSocket.cc que hacen una
    serie de “define” no compatibles en todas las versiones. En nuestro caso,
    ha sido necesario comentarlas ya que tenemos instalada la versión 1.0.6 y
    no la 1.0.7 o posterior.

    6) Comprobamos que todo está correcto compilando y ejecutando los test
    que incluyen el .src.tar.gz (SCTPTest.java y SCTPTest2.java).
    · Compilación:
    javac SCTPTest.java
    · Ejecución:
    java -cp . -Djava.library.path=. -verbose:jni -Xcheck:jni SCTPTest

    ResponderEliminar
  23. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  24. thans, Try it but still have same error

    I try what did you say but no succes. I am using ubun 10.04 with jdk 1.6

    I try the same thing with Netbeans, I give a link for JAR Library but sttill same error

    Exception in thread "main" java.lang.UnsatisfiedLinkError: no dk_i1_sctp in java.library.path


    so what I did wrong

    ResponderEliminar
  25. Hi Amina,
    I made this application some years ago and I don't have the environment to try reproduce your problem.
    I'm sorry but I can't help you much more with this configuration problems.

    Jorge.

    ResponderEliminar
  26. Hola Jorge. Soy nuevo en este tipo de código. También me interesa mucho saber de este código porque quiero desarrollar para mi web una aplicación de streaming (audio y video), en principio. Aunque lo ideal, lo que quiero conseguir es esto:

    http://intecca.uned.es/portalavip/emision_dif.php?id=248

    Me gustaría que me orientaras un poco y que me dijeras si con los códigos que pones arriba para descargar se podría conseguir algo de lo quiero o todo.

    Un saludo.
    Espero respuestas. Estaré visitando este blog constantemente.

    ResponderEliminar
    Respuestas
    1. Hola,
      construir una aplicación con java utilizando JMF es relativamente sencillo, sobre todo, si no necesitas sustituir la capa de transporte como tuve que hacer yo (de TCP/UDP a SCTP). De hecho, cuando yo estuve con este desarrollo me descargué un PDF que viene con ejemplos muy completos que seguro te servirán para hacer la aplicación que quieres. Supongo que lo que querrías hacer, mas o menos es, impartir una clase desde tu PC por lo que tendrás que recoger los "media" de audio y video utilizando los ejemplos que hay para recoger audio de micrófono y video de una cámara y luego seguir un poco los pasos que pongo yo arriba, solo que tu entrada de datos no es un video ya almacenado en el PC. El otro cambio básico será que la aplicación cliente deberá conectarse a la URL que especifiques para ver el contenido en tiempo real.
      En conclusión, creo que con JMF puedes hacer todo lo que quieres, pero tendrás que dedicarle unas cuantas horas a crear tu aplicación servidora y la que utilizarán los clientes que quieran conectarse. De hecho, quizá no haga falta ni que los clientes utilicen una aplicación realizada en JMF, quizá el mismo VLC que permite escuchar streaming desde una URL sirva.

      Espero haber sido de ayuda.
      Un saludo y suerte con tu aplicación ;)

      Eliminar
    2. Me gustaría que nos ayudaras más en esta aplicación. Por lo que te propongo que participes con nosotros. Somos un grupo de personas que estamos desarrollando el proyecto. Es un proyecto muy ambicioso. Hay muchas horas de trabajo realizadas en cuanto a diseño de código visual e interno, pero en el equipo necesitamos a una persona que aporte los conocimientos que vemos en ti (JMF).

      Hemos estado hablando en el equipo y la verdad que nos gustaría mucho tenerte.

      Si la respuesta es afirmativa tan solo tienes que hacerlo constar mediante una respuesta a este comentario y ya te facilitaremos un email de contacto, mediante el cual trabajamos todos. (Te podremos enseñar el proyecto y demás para que veas que es algo muy serio.)

      Estaré visitando el blog constantemente. (Perdón por el retraso en contestar pero perdí la dirección del blog y estuve varios días buscando por Google.)

      Saludos.

      Eliminar
  27. Buenas,
    agradezco mucho tu oferta, pero no creo que actualmente os pudiese dedicar mucho tiempo pues me encuentro trabajando en dos proyectos y realizando un curso por las tardes. En cualquier caso, no tengo ningún problema en ayudaros en la medida de lo posible aunque hace tiempo que dejé de programar. He enfocado mi carrera profesional más hacia sistemas y redes...
    Por si lo prefieres, mi email es morixan@hotmail.com.

    De nuevo, gracias por el comentario.

    ResponderEliminar