L'API JMF : API RTP


But de l'API

Cette API a pour but de permettre de gérer et transmettre un flux RTP en Java. On va pouvoir, grâce à celle-ci, développer son propre serveur de streaming et ainsi centraliser et distribuer de l'audio ou de la vidéo. Elle va nous permettre également de choisir les traitements effectués (compression, effet ...) afin de déterminer le type de flux que l'on souhaite transmettre. enfin on pourra capturer des flux multimédia provenant de périphériques(micro,caméra) et les retransmettre directement sur le réseau et ainsi mettre en place des applications de multi-conférences.

Son fonctionnement

L'API va nous permettre de gérer des sessions RTP très simplement. Tout d'abord comme pour l'API de base JMF, elle fournit une classe Manager "RTPManager" qui centralise toutes les fonctions liées à une session RTP. Cette classe va alors nous permettre l'envoi et la réception de flux RTP.

Réception d'un flux RTP :

L'accès à une ressource par un serveur RTP se fait en utilisant une adresse spécifique de la forme rtp://[adresse ip]:[port]/[type]/. On peut alors créer un objet MediaLocator à partir de cette adresse qui sera utilisé comme source du flux RTP. On peut ensuite utiliser l'API de base JMF pour présenter le flux arrivant dans une application ou une applet.

Envoi d'un flux RTP :

Dans un premier temps l'objet Processor va nous permettre d'appliquer les traitements nécessaires avant la transmission sur le réseau. On va alors pouvoir paramétrer le type d'encodage, la qualité et tout les paramètres liés au fichier que l'on souhaite transporter. Une fois ces traitements effectués sur le fichier on utilise le PushDatasource qu'il nous renvoie en sortie pour créer les flux d'envoie. Le RTPManager nous permet alors de créer une session RTP pour chaque flux que l'on souhaite transiter.

RTP par l'exemple

Dans cet exemple on effectuera aucun traitement supplémentaire sur le fichier. Il s'agit juste de montrer les opérations de base. De plus, l'exemple est codé de façon statique dans le seul but de tester les fonctionnalités de l'API. Un serveur opérationnel devra être codé plus proprement.


import javax.media.*;
import javax.media.rtp.*;
import javax.media.format.*;
import javax.media.control.*;
import javax.media.protocol.*;


public class StreamingServer {
	
		
	public static void main(String[] args) 
	{
//		Chemin du fichier
		String FichierAdresse = "file:////D://Java//Test.avi";
		
//		Création du MediaLocator à partir du fichier
		MediaLocator FichierLocator = new MediaLocator(FichierAdresse);
		
//		Déclaration du processeur
		Processor FichierCessor = null;
		DataSource ds=null;
		try{
			//Création du Processor à partir du MediaLocator
			try{
				ds = Manager.createDataSource(FichierLocator);
			}
			catch(Exception e){}  
			FichierCessor = Manager.createProcessor(ds);  
			//Appel des fonctions qui vont permettre le lancement du flux RTP
			configure(FichierCessor);
			SetSupportedFormat(FichierCessor);
			//passer dans l'etat realized du processor
			realize(FichierCessor);
			//start     
			Demarre(FichierCessor); 
			launchRTPManager(FichierCessor);
		}
		catch(IOException e)
		{
			System.out.println("Erreur : "+e.getMessage());
		}
		catch(NoProcessorException e)
		{
			System.out.println("Erreur : "+e.getMessage());
		}
	}
	
	public static Processor configure(Processor p)	
	{
		//Attendre tant que le Processor n'est pas configuré.
		while(p.getState() < Processor.Configured)
		{
			//Configuration du Processor
			p.configure();
		}
		return p;
	}
	
	public static void SetSupportedFormat(Processor p)
	{
		//On met la description du contenu de sortie à RAW_RTP
		ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
		p.setContentDescriptor(cd);
		
		//On obtient les différentes pistes du processor
		TrackControl track[] = p.getTrackControls();
		for(int i = 0 ; i < track.length ; i++)
		{
			//on obtient les formats supportés pour cette piste
			Format suppFormats[] = track[i].getSupportedFormats();
			//Si il y a au moins un format supporté
			if(suppFormats.length > 0)
			{
				track[i].setFormat(suppFormats[0]);
				System.err.println("Track " + i +" est transmis as :"+suppFormats[0]);
			}
			else
			{
				track[i].setEnabled(false);
			}
		}
	}
	
	public static Processor realize(Processor p)
	{
		//Attendre tant que le Processor n'est pas réalisé.
		while(p.getState() < Processor.Realized)
		{		
			//Réalisation du Processor
			p.realize();
		}
		return p;
	}
	
	public static void Demarre(Processor p)
	{
		//Demarrage du Processor
		p.start();
		System.err.println("started");
	}
	
	public static void launchRTPManager(Processor p)
	{
		//Creation du DataSource correspondant au Processor
		DataSource OutputSource = p.getDataOutput();
		PushBufferDataSource pbds = (PushBufferDataSource)OutputSource;
		PushBufferStream pbss[] = pbds.getStreams();              
		//Nouvelle Instance d'un RTPManager      
		RTPManager rtpm[] = new RTPManager[pbss.length];
		
		//System.out.println("taille:" +pbss.length);
		//RTPManager rtpm;
		for(int i=0; i < pbss.length;i++)	
		{
			try{
				rtpm[i] = RTPManager.newInstance();
				int port = 22224 + 2*i;
				//Création d'une SessionAddress 
				SessionAddress localaddr = new SessionAddress
				(InetAddress.getLocalHost(),port);
				//Initialisation du RTPManager 
				rtpm[i].initialize(localaddr);
				//Création d'une SessionAddress 
				SessionAddress destaddr = new SessionAddress
				(InetAddress.getByName("192.168.1.12"),port);
				
				//Ajout de cette SessionAddress dans le RTPManager
				rtpm[i].addTarget(destaddr);
				System.err.println("Creation RTP session 192.168.1.12 port : "+port);                     
				//Creation d'un SendStream à partir du DataSource				
				SendStream ss2 = rtpm[i].createSendStream(OutputSource,i);
				//Demarrage du SendStream
				ss2.start();
				System.out.println("Started ");
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}      
			
		}	
	}
}

Un autre exemple effectuant des traitement additionnels et développé par sun : Transmit