Mis à jour le jeudi 13 avril 2017
  • 40 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Ce cours existe en eBook.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

L'audio et la vidéo

Connectez-vous ou inscrivez-vous pour bénéficier de toutes les fonctionnalités de ce cours !

Une des grandes nouveautés du HTML5 est l'apparition des éléments <audio> et <video>, qui permettent de jouer des sons et d'exécuter des vidéos, le tout nativement, c'est-à-dire sans plugins tels que Flash, QuickTime ou même Windows Media Player. Nous allons donc voir ici comment interagir, via le JavaScript, avec ces deux éléments !

Pour bien comprendre ce chapitre, il serait bon que vous ayez quelques notions sur ces deux éléments HTML. Nous vous invitons à lire le chapitre La vidéo et l'audio du tutoriel de M@teo21 sur le HTML5. C'est important, car nous ne reviendrons que très sommairement sur l'utilisation « HTML » de ces deux éléments : ici on s'occupe du JavaScript !

L'audio

Les éléments <audio> et <video> se ressemblent fortement. D'ailleurs, ils sont représentés par le même objet, à savoir HTMLMediaElement. Comme ils dérivent du même objet, ils en possèdent les propriétés et méthodes.

L'insertion d'un élément <audio> est très simple.

<audio id="audioPlayer" src="hype_home.mp3"></audio>

Ce bout de code suffit à insérer un lecteur audio qui lira le son hype_home.mp3. Mais, nous, nous n'allons pas utiliser l'attribut src, mais plutôt deux éléments <source>, comme ceci :

<audio id="audioPlayer">
    <source src="hype_home.ogg">
    <source src="hype_home.mp3">
</audio>

De cette manière, si le navigateur est capable de lire le format .ogg, il le fera. Sans quoi, il lira le format .mp3. Ça permet une plus grande interopérabilité (compatibilité entre les navigateurs et les plates-formes).

Pour afficher un contrôleur de lecteur, il faut utiliser l'attribut booléen controls, comme ceci : <audio controls="controls"></audio>. Mais ici, c'est un cours de JavaScript, donc nous allons créer notre propre contrôleur de lecture !

Contrôles simples

Voyons pour commencer comment recréer les boutons « Play », « Pause » et « Stop ». On commence par accéder à l'élément :

var player = document.querySelector('#audioPlayer');

Si on veut lancer la lecture, on utilise la méthode play() :

player.play();

Si on veut faire une pause, c'est la méthode pause() :

player.pause();

Par contre, il n'y a pas de méthode stop(). Si on appuie sur un bouton « Stop », la lecture s'arrête et se remet au début. Pour ce faire, il suffit de faire « Pause » et d'indiquer que la lecture doit se remettre au début, avec la propriété currentTime, exprimée en secondes :

player.pause();
player.currentTime = 0;

On va créer un petit lecteur, dont voici le code HTML de base :

<audio id="audioPlayer">
    <source src="hype_home.ogg">
    <source src="hype_home.mp3">
</audio>

<button class="control" onclick="play('audioPlayer', this)">Play</button>
<button class="control" onclick="resume('audioPlayer')">Stop</button>

Deux boutons ont été placés : le premier est un bouton « Play » et « Pause » en même temps (comme sur la plupart des lecteurs modernes), et le second permet de stopper et de rembobiner la lecture. Voici les fonctions play et resume :

function play(idPlayer, control) {
    var player = document.querySelector('#' + idPlayer);
	
    if (player.paused) {
        player.play();
        control.textContent = 'Pause';
    } else {
        player.pause();	
        control.textContent = 'Play';
    }
}

function resume(idPlayer) {
    var player = document.querySelector('#' + idPlayer);
	
    player.currentTime = 0;
    player.pause();
}

Le fonctionnement du bouton « Play » est simple : avec la méthode paused, on vérifie si la lecture est en pause. En fonction de ça, on fait play() ou pause(), et on change le libellé du bouton.

Essayer le code

Contrôle du volume

L'intensité sonore se règle avec la propriété volume sur une échelle allant de 0 à 1. Si le volume est à 0, il est muet, et s'il est à 1, il est à fond. Pour le diminuer de moitié, on mettra 0,5. On va faire un système très simple : cinq barres verticales cliquables qui permettent de choisir un niveau sonore prédéfini :

<span class="volume">
    <a class="stick1" onclick="volume('audioPlayer', 0)"></a>
    <a class="stick2" onclick="volume('audioPlayer', 0.3)"></a>
    <a class="stick3" onclick="volume('audioPlayer', 0.5)"></a>
    <a class="stick4" onclick="volume('audioPlayer', 0.7)"></a>
    <a class="stick5" onclick="volume('audioPlayer', 1)"></a>
</span>

Et la fonction associée :

function volume(idPlayer, vol) {
    var player = document.querySelector('#' + idPlayer);
	
    player.volume = vol;	
}

Essayer le code

Barre de progression et timer

Un lecteur sans une barre de progression n'est pas un lecteur ! Le HTML5 introduit un nouvel élément destiné à afficher une progression : l'élément <progress>. Il n'est toutefois utilisable qu'avec Firefox et Chrome. Mais nous n'allons pas l'utiliser ici, car cet élément n'est pas facilement personnalisable avec du CSS. On l'utilisera plus tard dans le chapitre sur l'API File.

Nous allons donc créer une barre de progression « à la main », avec des <div> et quelques calculs de pourcentages !

Ajoutons ce code HTML après l'élément <audio> :

<div>
    <div id="progressBarControl">
        <div id="progressBar">Pas de lecture</div>
    </div>
</div>
Analyser la lecture

Un élément HTMLMediaElement possède toute une série d'événements pour analyser et agir sur le lecteur. L'événement ontimeupdate va nous être utile pour détecter quand le média est en train d'être joué par le lecteur. Cet événement est déclenché continuellement pendant la lecture.

Ajoutons donc cet événement sur notre élément <audio> :

<audio id="audioPlayer" ontimeupdate="update(this)">

Et commençons à coder la fonction update() :

function update(player) {
    var duration = player.duration;    // Durée totale
    var time     = player.currentTime; // Temps écoulé
    var fraction = time / duration;
    var percent  = Math.ceil(fraction * 100);

    var progress = document.querySelector('#progressBar');
	
    progress.style.width = percent + '%';
    progress.textContent = percent + '%';
}

L'idée est de récupérer le temps écoulé et de calculer un pourcentage de manière à afficher la barre de progression (qui fait 100 % de large). Donc, si la chanson dure dix minutes et qu'on en est à une minute de lecture, on a lu 10 %.

La propriété duration sert à récupérer la durée totale du média. Le calcul est simple : on divise le temps écoulé par la durée totale et on multiplie par 100. Comme ça ne tombera certainement pas juste, on arrondit avec Math.ceil(). Une fois le pourcentage récupéré, on définit la largeur de la barre de progression, et on affiche le pourcentage à l'intérieur.

Le petit lecteur est désormais terminé !

Essayer le code

Améliorations

L'interface réalisée précédemment est fonctionnelle, mais rudimentaire. Deux améliorations principales sont possibles :

  • Afficher le temps écoulé ;

  • Rendre la barre de progression cliquable.

Afficher le temps écoulé

Afficher le temps écoulé ? Ce n'est pas compliqué, il suffit d'utiliser la propriété currentTime. Le souci est que currentTime retourne le temps écoulé en secondes avec ses décimales. Il est donc possible de voir s'afficher un temps de lecture de 4,133968 secondes. Il convient donc de faire quelques opérations pour rendre ce nombre compréhensible. Voici la fonction formatTime() :

function formatTime(time) {
    var hours = Math.floor(time / 3600);
    var mins  = Math.floor((time % 3600) / 60);
    var secs  = Math.floor(time % 60);
	
    if (secs < 10) {
        secs = "0" + secs;
    }
	
    if (hours) {
        if (mins < 10) {
            mins = "0" + mins;
        }
		
        return hours + ":" + mins + ":" + secs; // hh:mm:ss
    } else {
        return mins + ":" + secs; // mm:ss
    }
}

On opère quelques divisions et arrondissements afin d'extraire le nombre d'heures, de minutes et de secondes. Puis on complète avec des 0 pour un affichage plus joli.
On peut donc ajouter ceci à notre fonction update() :

document.querySelector('#progressTime').textContent = formatTime(time);

Et modifier la barre de progression pour y ajouter un <span> dans lequel s'affichera le temps écoulé :

<div id="progressBarControl">
    <div id="progressBar">Pas de lecture</div>
</div>
<span id="progressTime">00:00</span>

Rendre la barre de progression cliquable

Ici, ça se corse un peu. Si on clique sur la barre de progression, le comportement attendu est la lecture du fichier audio à partir de cet endroit. Il va donc falloir calculer l'endroit où on a cliqué et positionner la lecture en conséquence, avec la propriété currentTime.

Pour savoir où l'on a cliqué au sein d'un élément, il faut connaître deux choses : les coordonnées de la souris et les coordonnées de l'élément. Ces coordonnées sont calculées à partir du coin supérieur gauche de la page. Voici une explication plus imagée :

Les coordonnées sont calculées à partir du coin supérieur gauche de la page
Les coordonnées sont calculées à partir du coin supérieur gauche de la page

Pour connaître la distance représentée par la flèche turquoise, il suffit de soustraire la distance représentée par la flèche rouge (la position de la barre sur l'axe des X) à la distance représentée par la flèche bleue (la position X du curseur de la souris). C'est tout simple, mais la récupération des coordonnées n'est pas évidente.

Récupérer les coordonnées du curseur de la souris

Nous allons créer la fonction getMousePosition() qui recevra comme paramètre un événement et qui retournera les positions X et Y du curseur :

function getMousePosition(event) {
    return {
        x: event.pageX,
        y: event.pageY
    };
}

Les propriétés pageX et pageY de l'objet event permettent respectivement de récupérer les positions sur l'axe des X et sur l'axe des Y.

Essayer le code

Récupérer les coordonnées d'un élément

Comme l'élément n'est pas positionné de façon absolue, il n'est pas possible de connaître les coordonnées de son coin supérieur gauche via le CSS. Il va donc falloir calculer le décalage entre lui et son élément parent, puis le décalage entre cet élément parent et son parent… et ainsi de suite, jusqu'à arriver à l'élément racine, c'est-à-dire <html> :

function getPosition(element){
    var top = 0, left = 0;
    
    do {
        top  += element.offsetTop;
        left += element.offsetLeft;
    } while (element = element.offsetParent);
    
    return { x: left, y: top };
}

Si vous ne connaissez plus le rôle des propriétés offsetLeft, offsetTop et offsetParent, nous vous conseillez de revenir sur la partie qui aborde le sujet dans le chapitre sur la manipulation du CSS.

On clique !

Maintenant que nous avons nos deux fonctions getMousePosition() et getPosition(), nous pouvons écrire la fonction clickProgress(), qui sera exécutée dès que l'internaute cliquera sur la barre de progression :

function clickProgress(idPlayer, control, event) {
    var parent = getPosition(control);    // La position absolue de la progressBar
    var target = getMousePosition(event); // L'endroit de la progressBar où on a cliqué
    var player = document.querySelector('#' + idPlayer);
  
    var x = target.x - parent.x; 
    var wrapperWidth = document.querySelector('#progressBarControl').offsetWidth;
    
    var percent = Math.ceil((x / wrapperWidth) * 100);    
    var duration = player.duration;
    
    player.currentTime = (duration * percent) / 100;
}

On récupère la distance x, qui est la distance entre le bord gauche de la barre et l'endroit où on a cliqué. On divise x par la largeur totale du conteneur de la barre de progression (avec offsetWidth) et on multiplie par 100 pour obtenir un pourcentage. Ensuite, on calcule le currentTime en multipliant le temps total de la chanson par le pourcentage, le tout divisé par 100.

Et n'oublions pas de modifier le code HTML en conséquence :

<div id="progressBar" onclick="clickProgress('audioPlayer', this, event)">Pas de lecture</div>

Et ça marche !

Essayer le code

La vidéo

Il n'y a pas grand-chose à ajouter en ce qui concerne les vidéos. Le principe de fonctionnement est exactement le même que pour les lectures audio. L'élément <video> possède toutefois quelques propriétés en plus :

Propriété

Description

height

Hauteur de la zone de lecture

width

Largeur de la zone de lecture

poster

Récupère l'attribut poster

videoHeight

La hauteur de la vidéo

videoWidth

La largeur de la vidéo

En dehors de ça, la création et la personnalisation de la lecture d'une vidéo est rigoureusement identique à celle d'une piste audio.

Il peut être utile d'utiliser un framework JavaScript destiné à la lecture d'éléments <audio> et <video> afin se faciliter la vie. De plus, ce genre de framework propose généralement une solution en Flash si le navigateur n'est pas à la hauteur du HTML5.

Voici quelques frameworks qu'il peut être intéressant de considérer :

En résumé
  • Les éléments <audio> et <video> possèdent tous les deux de nombreux attributs et méthodes afin que chacun puisse créer un lecteur entièrement personnalisé.

  • La différence entre les deux éléments est minime. Ils sont tous les deux basés sur le même objet, l'élément <video> n'apporte que quelques attributs supplémentaires permettant de gérer l'affichage.

  • Contrairement au Flash, la protection du contenu n'existe pas (encore) avec ces deux éléments. Réfléchissez donc bien avant d'écarter définitivement toute solution avec Flash !

Exemple de certificat de réussite
Exemple de certificat de réussite