Nous avons présenté dans notre précédent article les principaux concepts et l’architecture générale de RTCWeb. Nous abordons maintenant dans ce billet, l’API WebRTC, qui va permettre aux applications s’exécutant dans les navigateurs Web d’exploiter toutes ces fonctions. Cette API, encore à l’état de working draft, est développée par le W3C (World Wide Web Consortium) et utilise de nombreux éléments introduits en HTML5 (balise video par exemple).
Notre objectif dans cet article est de décrire le fonctionnement global de l’établissement de session entre deux navigateurs. L’implémentation d’une telle fonction repose sur 3 phases principales: l’acquisition des ressources audio/vidéo dans le navigateur de l’émetteur, la transmission de ces flux sur le réseau et le rendu sur le navigateur du récepteur. Nous décrivons ainsi les deux principales primitives WebRTC permettant d’atteindre ce but: la Stream API qui permet la manipulation de ressources multimédias et l’interface PeerConnection qui assure la communication à travers le réseau. Nous présentons les principes généraux de ces deux primitives sans rentrer, à ce stade, dans les détails de l’API car ces derniers ne sont pas stabilisés et vont encore faire l’objet de nombreuses modifications.
Stream API
La Stream API, et en particulier son objet MediaStream, est au cœur du fonctionnement de WebRTC. Toute la partie multimédia passe par elle, quelle que soit la source et la destination du trafic.
Un flux média (media stream en anglais) contient et traite les pistes audio et vidéo. Ces flux peuvent provenir de différentes sources (locales ou distantes), et sont émis à des destinations variables (locales ou distantes également). Au sein de cette interface, seul l’objet MediaStream reste immuable quelle que soit le cas de figure considéré.
Les différentes étapes illustrées sur la figure ci-dessus sont les suivantes:
1. Construction de l’object MediaStream
L’objet MediaStream prend en paramètre soit une connexion distante (PeerConnection, voir ci-après), soit un objet LocalMediaStream ayant accès aux ressources locales du terminal. Ces accès, pour des raisons de sécurité, doivent être explicitement donnés par l’utilisateur au cas par cas, via l’usage de boutons (« Diffuser ma vidéo » pour autoriser le flux vidéo par exemple) ou par des préférences dédiées à chaque page et gérées par le navigateur. La fonction getUserMedia() récupère, simultanément ou séparément (il est possible de l’appeler plusieurs fois), les différentes sources afin de les traiter par la suite.
2. Sources locales
Ces ressources peuvent émaner de différentes origines, notamment d’équipements de capture en temps réel (microphone, webcam, caméra …) ou de fichiers locaux au terminal. Le support de ces différentes sources est assurée grâce aux nouvelles fonctionnalités offertes par HTML5 (File API, Media Capture).
3. Gestion des différents flux
Un MediaStreamTrack est créé pour chacun des flux, audio ou vidéo. Puisqu’il peut exister de multiples flux simultanés (plusieurs microphones distincts par exemple), ceux-ci sont stockés au sein de listes de type MediaStreamTrackList. Ces listes sont utilisées pour créer le flux média (MediaStream). Il est ici intéressant de noter plusieurs points :
- Grâce à ces listes, l’objet MediaStream est dynamique. Il devient en effet possible d’ajouter et de retirer à la volée des flux multimédias sans avoir besoin de recréer un nouvel objet (fonction add() de l’objet MediaStreamTrackList).
- Les pistes audio peuvent contenir un nombre variables de canaux (mono, stéréo, 5.1 …), permettant leur utilisation dans de multiples situations différentes. Ces canaux sont les plus petites unités d’un MediaStream.
4. Utilisation du MediaStream
Cet objet MediaStream peut ensuite être utilisé dans divers cas de figures :
- le flux peut être directement affiché dans le navigateur local, ce qui peut servir à afficher le retour d’une webcam locale ou le flux en provenance d’un tiers via un objet PeerConnection en entrée;
- les flux peuvent être enregistrés dans des fichiers locaux;
- les flux peuvent être envoyés à un tiers à l’aide d’un objet PeerConnection, ce qui est est l’objectif même de WebRTC.
La pratique veut que ces objets MediaStream disposent d’un URL pour l’objet binaire qu’il représente (BLOB ou Binary Large OBject). La fonction createObjectURL crée cet URL. Les données de l’objet que cet URL représente doivent être compréhensibles directement par les éléments HTML5 audio ou video.
Dernier point intéressant au sujet de cette Stream API, il est possible d’adjoindre à ce schéma général un objet MediaStreamRecorder permettant, comme son nom le laisse suggérer, d’enregistrer en temps réel les flux audio/vidéo. Cet enregistrement est représenté sous la forme d’un BLOB. Cet enregistreur doit être capable de gérer efficacement l’ajout ou la suppression de MediaStreamTrack du flux multimédia.
Pour plus d’informations sur la gestion des fichiers et des BLOB, se référer à la File API.
La figure ci-dessous illustre un cas d’usage typique du fonctionnement de MediaStream. La fonction getUserMedia() (1), déclenchée par un bouton, autorise l’accès aux différents équipements (microphone, webcam …) (2) afin d’en récupérer les flux audio/vidéo. Ces LocalMediaStream ou MediaStreamTrack sont traité par la fonction appelée (callback) en cas de succès, afin de les ajouter aux MediaStreamTrackList d’un objet MediaStream, créant effectivement le flux média. Celui-ci peut ensuite être ajouté à une connexion sortante (4) PeerConnection afin de transmettre le flux à un destinataire.
PeerConnection API
Si l’objet MediaStream discuté précédemment est incontournable pour la manipulation des flux multimédias, l’objet PeerConnection de son côté est primordial pour l’établissement d’une connexion, de manière transparente, entre deux entités RTCWeb. Définie au sein de la même spécification que la Stream API, cette API risque d’être altérée en profondeur dans les mois à venir puisque l’IETF est en train de définir un framework d’établissement de session pour RTCWeb/WebRTC (JSEP ou Javascript Session Establishment Protocol actuellement en draft00) qui va avoir un impact certain sur les routines de l’objet PeerConnection. Partant de ce constat, nous faisons ici le choix de n’énoncer que les éléments généraux qui seront probablement traités par l’objet, d’une manière ou d’une autre.
L’objet PeerConnection gère l’ensemble de l’établissement de connexion avec la partie distante. Actuellement, comme décrit dans la figure ci-dessus, lors de sa création, il est possible de remarquer qu’il prend deux paramètres qui traitent de deux aspects bien distincts :
- Son premier paramètre spécifie un serveur STUN/TURN pour la traversée de NAT des flux multimédias qui systématiquement tentée par l’usage d’ICE.
- Son second paramètre définit la fonction à appeler (callback) pour envoyer des messages de signalisation. Il est dès lors possible de manipuler et personnaliser les messages envoyés au destinataire via cette fonction.
La signaling callback passée en second paramètre permet de générer les messages de signalisation, nécessaires pour échanger les informations de connexion, grâce à SDP. Le protocole de signalisation en lui-même (SIP, Jabber/Jingle, propriétaire) est laissé au libre choix de l’implémentation. Afin de permettre l’utilisation de SIP dans ce cadre, un draft est en discussion au sein de l’IETF afin d’ajouter un transport de type WebSocket au protocole SIP.
Encore peu utilisé au sein de la VoIP actuellement, le protocole ICE va gagner, avec ces implémentations, ses lettres de noblesse puisqu’il prend ici une place centrale dans la traversée des NAT des flux multimédias. Si les détails de son fonctionnement sortent du cadre de cet article, rappelons toutefois qu’il a pour objectif de négocier automatiquement et de manière totalement transparente la connexion en effectuant de multiples tests de connectivité entre les deux terminaux (ici, les navigateurs) après avoir récupéré son adresse publique et une éventuelle adresse relai grâce respectivement au serveur STUN ou TURN passé en paramètre. L’efficacité de ce protocole n’est plus à prouver et son déploiement dans ce cadre renforce encore la facilité d’accès par les utilisateurs finaux aux applications développées sur cette base.
Démonstration basique
Afin d’illustrer cette API, nous vous présentons ci-dessous un exemple, très simple, d’utilisation de l’objet MediaStream, sans connexion à un hôte distant, mais en affichant le retour direct du flux d’une webcam connectée sur votre ordinateur. Seule une démonstration basique est proposée ici pour plusieurs raisons :
- La spécification est encore au stade de brouillon fonctionnel (working draft) et est donc fortement susceptible de changer à l’avenir. Notamment, l’objet PeerConnection est actuellement en pleine refonte, mais il est aussi probable que des modifications soient apportées à MediaStream également.
- Les implémentations sont expérimentales et souvent instables. En l’état ici, seuls les navigateurs expérimentaux Opera Labs Camera et Google Chrome Canary sont supportés. Si vous testez cette page avec ces navigateurs, ils doivent vous demander si vous souhaitez autoriser ou non l’usage de la webcam. A noter que Chrome Canary nécessite une configuration manuelle à l’adresse chrome://flags afin d’activer l’option MediaStream
Note: nous ne pouvons garantir un fonctionnement optimal de cette démonstration, ces fonctions étant expérimentales et susceptibles de changements à tout moment dans les implémentations.
Si cette démonstration est extrêmement basique, elle donne un aperçu de ce que ces deux APIs, relativement simples, peuvent offrir lorsque les implémentations seront finalisées et massivement déployées (téléphonie/visiophonie à partir d’un simple navigateur de manière standardisée, …). Les progrès réalisés au cours de ces derniers mois sont impressionnants et présagent du meilleur pour RTCWeb et son API, WebRTC. A suivre …