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