Flash Media Server, kesako

  • warning: array_map(): Argument #2 should be an array in /var/www/titouille.ch/www/modules/system/system.module on line 1050.
  • warning: array_keys() expects parameter 1 to be array, null given in /var/www/titouille.ch/www/includes/theme.inc on line 1845.
  • warning: Invalid argument supplied for foreach() in /var/www/titouille.ch/www/includes/theme.inc on line 1845.
Portrait de titouille

Sous ce nom un peu barbare (ou sous son acronyme "FMS") se cache ce qu'on appelle un serveur de streaming.

Tout d'abord, qu'est-ce qu'un serveur de streaming ? Un peu comme un serveur web, il permet de mettre à disposition des données. Mais des données de type média (mp3, flv) et surtout de gérer des flux en temps réel, l'idéal pour créer des application de tchat, visio-conférence, jeux en ligne, etc...

Pour la citer car je m'y intéresserai surement de plus près, il existe 2 serveurs de streaming de la sorte : FMS, la technologie macromedia / adobe, qui implique des licenses relativement onéreuses, ainsi que Red5, qui lui est un projet open-source hébergé par la communauté OSFlash. Red5 est l'équivalent de FMS, mais utilise le langage Java pour le développement côté serveur, alors que FMS utilise l'asc, son propre langage dérivé d'actionScript.

Pour entrer dans le vif du sujet, je passerai par dessus l'installation ou la configuration du serveur, rien de bien compliqué que d'exécuter une installation de software. Je m'appliquerai aujourd'hui à expliquer les grandes lignes du système, et la manière d'aborder un projet à développer sur un serveur de streaming. Faisons fi du code et arrêtons nous sur la manière.

Tout d'abord, voici les mots-clés qui vont nous faire avancer :

Application

L'application est l'objet de base. On développe tout à partir de l'application, qui se trouve généralement dans le fichier main.asc ou [monprojet].asc
C'est elle qui détient les gestionnaires d'évenements de base : onAppStart, onConnect, onConnectAccept, onConnectReject, onDisconnect, onStatus, onAppStop.

Chacun de ces évènements est appelé à un moment bien précis :

  • onAppStart : exécuté au lancement de l'application lors de la connexion du premier utilisateur
  • onConnect : exécuté à chaque fois qu'un utilisateur se connecte
  • onConnectAccept : exécuté lorsqu'un utilisateur est accepté dans l'application
  • onConnectReject : exécuté lorsqu'un utilisateur est rejeté de l'application (il ne passe pas les tests de sécurité)
  • onDisconnect : exécuté à chaque fois qu'un utilisateur se déconnecte
  • onStatus : exécuté lorsque le serveur rencontre une erreur
  • onAppStop : exécuté lorsque l'application se détruit (lorsque le dernier utilisateur en sors)

Nous allons voir par la suite que ces différents évenements seront très utiles pour gérer les utilisateurs sur notre serveur.

Instance

L'instance est une sorte d'objet qui se crée automatiquement lors d'une connexion sur un serveur FMS :
Pour se connecter à l'application, on utilisera par exemple l'url rtmp://www.monserveur.com/monapplicationfms. Pour créer une nouvelle instance dynamiquement, on va rajouter le nom de l'instance à créer dans l'url : rtmp://www.monserveur.com/monapplicationfms/moninstance

L'instance créée par cette méthode est une instance de notre application, mais une instance distincte. On peut en créer autant qu'on veut, en modifiant à chaque fois le nom utilisé dans l'url. Il m'a néanmoins été conseillé de ne pas trop abuser des instances et de travailler avec les "Rooms" que j'expliquerai ci-dessous.

Shared Object

Quel Flasheur ne connait pas les objets partagés (shared object ou SO). Cette classe permet d'enregistrer des données sur le disque dur côté client, afin qu'il puisse les récupérer lors d'une utilisation ultérieure de notre application. Et bien avec FMS, il existe des objets partagés côté serveurs. Qui dit "partagés" implique que plusieurs personnes peuvent se connecter dessus en même temps.

L'objet partagé côté serveur est une sorte de "radio" qui émet des informations. Tous les gens qui se connectent à cette "radio" peuvent envoyer des informations en faveur des autres connectés, et recevoir les informations envoyées par les autres connectés. L'objet partagé possède un évènement particulier nommé "onSync" qui est déclenché chaque fois qu'une donnée change dans l'objet partagé. Cet évènement est envoyé à tous les "écouteurs" ( tiens, je me croirai en train d'écouter le générique de la planète bleue sur Couleur3 Laughing out loud )

C'est lorsque j'ai commencé à fouiller tout ça en profondeur que j'ai compris le concept de...

Room

C'est maintenant que les choses deviennent relativement intéressantes, au niveau de la mise en place.

Une "Room", ou Salle, est un concept abstrait. Il n'existe pas de classe Room ou d'objet de ce genre dans FMS. En réalité, il faut prendre un exemple de projet pour comprendre l'imbrication des différents éléments.

Admettons le projet suivant : je désire créer un système de chatroom ou l'utilisateur va arriver sur une page listant les salles, choisir celle dans laquelle il veut entrer, être redirigé dans cette dernière et pouvoir commencer à discuter avec les résidents.

Dès lors que nous parlons de "discussion", un objet partagé va entrer en jeu, car c'est lui qui fait office de "radio" et qui va diffuser les messages envoyés par chaque utilisateur. Il n'est par contre nul besoin de chercher longtemps. Qui dit "plusieurs salles" dit "plusieurs objets partagés".

Rappelons-nous le concept d'un objet partagé. je me connecte, je peux y envoyer des informations et les autres les recevront, et je peux recevoir les informations que les autres y envoient. Celà implique que tous les utilisateurs connectés sur un même objet partagés recevront tous les messages des autres utilisateurs. Mais ce n'est pas notre but, nous voulons des salles précises, qui vont permettre de lancer des sujets de discussions différents, regrouper des ensembles de personnes différentes, etc...

Avec un peu de réflexion et ces explications, on peut comprendre qu'une salle, en fin de compte, se résumerai presque à un objet partagé. C'est l'objet partagé qui permet de faire la liaison entre les utilisateurs.

Voilà donc ou se situe l'astuce de ce système :

Il est possible de développer une classe "Room" qui va contenir différentes propriétés et objets :

son nom (son identifiant),
un objet partagé sur lesquels les utilisateurs vont se connecter,
un tableau qui va contenir les "clients"
des méthodes "createRoom", "removeRoom", "addUser" et "removeUser"

Et c'est maintenant que nous allons revenir sur les gestionnaires de la classe "Application".

Processus standard :

1. le client lance son animation Flash qui va tenter une connexion au serveur
2. onAppStart est appelé, l'application est créée et ses objets initialisés
3. (admettons que l'utilisateur se connecte sans authentification) onConnect est appelé, nous récupérons l'objet "client", nous regardons dans quelle salle il veut entrer, nous créons la salle au besoin (new Room( roomid) ) et enfin, nous appelons sa méthode "addUser" pour y ajouter l'utilisateur.
4. Dans la méthode addUser de notre classe Room, le plus important est simplement d'ajouter notre utilisateur à notre objet partagé, permettant ainsi de faire la liaison entre l'utilisateur et la salle qu'il a choisi. Il est maintenant a même de pouvoir intercepter les messages des autres et envoyer les siens.
...
...
5. l'utilisateur se déconnecte. onDisconnect est appelé. Nous allons retirer l'utilisateur de sa salle via la méthode "removeUser", et supprimer la salle si plus personne ne s'y trouve (removeRoom). RemoveUser va dans tous les cas supprimer notre utilisateur de l'objet partagé, ainsi il n'est plus connecté à la salle.

Dans les grandes lignes, le principe est là.
Maintenant, différentes choses à prendre en compte...
Il faut bien se mettre en tête que mis à part ces classes que FMS met à notre disposition, nous devons développer de A à Z les fonctionnalités serveur dont nous avons besoin.

Dans le cas du projet chatroom, il y a pas mal de points à prendre en compte, par exemple :

a. dès qu'un utilisateur se connecte et veut entrer dans une salle, on va stocker dans un tableau associatif la salle dans laquelle on le place. Ainsi lors d'un appel à "onDisconnect", je n'ai qu'a aller voir dans ce tableau pour savoir dans quelle salle il se trouve et pouvoir le supprimer sans avoir à itérer sur chaque salle pour le trouver.

b. je gère un "objet" client. Il existe une classe "Client" dont chaque instance correspond à un utilisateur connecté. Une instance de client possède les propriétés suivantes :

  • agent
  • ip
  • protocol
  • readAccess
  • writeAccess
  • referrer
  • secure
  • uri
  • virtualKey

Une instance de "Client" correspond à l'objet NetConnection instancié au niveau de l'application client.
Maintenant, il faut savoir qu'au niveau serveur, ce sont ces instances de "Client" qui sont les objets qu'ont doit affecter aux objets partagés.
Malgré ça, on aura souvent envie de rajouter de nouvelles propriétés à notre instance de client pour faire persister certaines données. Mais ce n'est pas une bonne pratique...
J'avais commencé par tout enregistrer dans mon instance de "Client", et je me suis rendu compte que dès que le client est connecté à l'objet partagé, tout le monde a accès à toutes ces informations.
Il est donc judicieux de créer, pour chaque utilisateur, un objet "oClient" qui va pouvoir contenir toutes les données nécessaires au bon fonctionnement de l'application, sans pour autant dévoiler ces informations à tous les utilisateurs.

Par exemple (reprise des 2 concepts ci-dessus) :

application.onConnect = function( client, username, password, room )
{
var oClient = new Object();
oClient.username = client.username = username;
oClient.password = password;
oClient.room = room;
oClient.client = client;
//
// ajout du client dans la salle demandée...
//
if( oRooms[room] == undefined )
oRooms[room] = new Room( room );
oRooms[room].addUser( oClient );
 
// stockage de la salle dans laquelle
// est connecté le client dans un tableau
oUsers[username] = room;
}

c. Lorsqu'un utilisateur se déconnecte de lui-même, la méthode onDisconnect est automatiquement appelée.
Il existe également un principe d'éjection : application.disconnect( client );
Ce dernier permet de déconnecter un utilisateur depuis le serveur (très utile pour des méthodes kick et ban, par exemple). Lorsqu'on appelle cette méthode au niveau serveur, le client est déconnecté de l'application ET la méthode onDisconnect est appelée.
Il n'est donc pas nécessaire de supprimer l'utilisateur après avoir appelé la méthode "disconnect" car de toute façon, le système de gestionnaire est pris en charge, et via onDisconnect, l'utilisateur sera supprimé de la salle comme si il s'était déconnecté de sa propre initiative. Il serait même malsain de supprimer l'utilisateur avant l'appel du gestionnaire onDisconnect, car lors de ce dernier, l'utilisateur ne sera plus existant et l'application pourra planter car elle ne le trouve plus.

En fait, le système est très bien en place et suis des règles bien précises. Il n'est pas très difficile de comprendre le fonctionnement, le plus dur étant de mettre en place un système cohérent Smile

Voilà pour aujourd'hui. J'espère que ce ticket aura permis de démystifier un peu Flash-Media-Server, sur lequel on trouve si peu de documentation et d'explications en français.

N'hésitez pas à donner votre avis ou a poser des questions si certaines informations restent obscures, je tenterai d'y répondre à hauteur de mes compétences Wink




Grand Merci

Merci Monsieur de cette explication aussi simplifiée et facile à comprendre.
En effet , il y a peu de tutoriel sur FMS en fr, votre document m' était très utile.
maintenant je doit chercher quelques choses sur Flash Media Streaming, une idée sur le streaming?

jb l 'envoie et la reception

jb l 'envoie et la reception de la video et l'audio.

dur dur

merci pour tes explications n empeche que c est dur
j ai installé un serveur FMS sur mon linux
version dev je n arrive meme pas à demarrer les
applis

Portrait de titouille

démarrer les applis

Hello Jean-Michel,

Est-ce que tu pourrais être un peu plus précis sur ce que tu n'arrive pas à faire ? Est-ce que tu as essayé de passer par l'admin (management console) pour voir si tu arrive à instancier une application ?? en général une appli démarre automatiquement dès qu'un utilisateur se connecte dessus, que ce soit toi via la console ou bien via une animation Flash directement.

Et surtout, est-ce que tu es sur que le serveur est bien démarré ? (sous linux, je ne sais pas, mais sous windows on peut le voir dans la liste des services exécutés sur la machine)

merci de ta réponse

en faite je suis parti loin de mon ordi pendant 2 semaines et quelque jours
j'avais progressé mais depuis j ai un peu perdu la mémoire de ce que j ai fait
je te tiens au courant dés que je m y remets

applis

oui le serveur est bien démarré
l'admin est la meme sur linux c'est du flash
j'avais réussi à démarrer des applis mais je ne me souviens c'est l'age ...
je les vois maintenant dans la liste
heureusement je connais le shell

suite

ça y est j'ai trouvé des exemples
et notamment un chat video que j'ai inclus dans mon chat PHP. ça roule

Viii !

Merci beaucoup c'est bien plus clair desormais... en théorie Smile Reste à appliquer tout ça je m'y penche !! Merci !

Merci !

Je viens de finir la lecture de ce post, et effectivement, cela m'a permis de "démystifier un peu Flash-Media-Server". Donc, merci !