Créer un player audio en HTML5, 2 : le prototype

Bon allez, on se lance dans la création de notre player audio personnalisé ! Dudley Storey utilise une approche par petits pas — ou plutôt par petits tests — pour construire un prototype.

Par

En toutes choses il existe généralement deux approches. La première consiste à se lancer la tête la première, à construire de haut en bas, à se débattre avec les problèmes à mesure qu’on les rencontre et à espérer que tout se terminera bien. La seconde consiste à partir de tests simples : on construit du bas vers le haut, et chaque étape doit être validée avant de générer un tout cohérent et qui fonctionne.

Il y a des avantages à chaque méthode, mais la seconde produit souvent de meilleurs résultats. J’utiliserai cette approche ici pour la construction du prototype initial du player audio web présenté dans la première partie de cette série.


image
Voir la démo en fin d’article

L’un des avantages d’héberger votre player est la possibilité de tout personnaliser : plutôt que d’avoir à se débrouiller avec l’interface utilisateur de SoundCloud ou avec l’interface native des navigateurs, nous pouvons créer la nôtre, avec des éléments HTML5 personnalisés et avec un minimum de connaissance de JavaScript. Le résultat final ne sera pas exactement la version montrée ci-dessus — que nous réaliserons dans les articles qui suivent — mais avec ce code nous ferons déjà une bonne partie du chemin.

Les éléments de départ

Tout d’abord, nous allons vérifier que nous pouvons bien jouer un fichier audio sur une page. Ici, j’utilise la piste 24 de Ghosts III, sous licence Creative Commons.

<figure id="audioplayer">
    <audio controls src="24-ghosts-III.mp3" id="audiotrack"></audio>
</figure>

La dernière version de Firefox est compatible avec .mp3 comme tous les navigateurs modernes, je n’utiliserai donc que ce codec. J’ai placé un élément <figure> autour de <audio> car nous allons ajouter quelques contrôles ainsi que des titres.

Une fois satisfaits du fonctionnement de l’audio, nous pouvons passer à la tâche suivante, la création de l’interface utilisateur personnalisée de notre player.

Travailler en amélioration progressive

Si notre utilisateur n’a pas JavaScript, ou si le script ne fonctionne pas, nous voulons qu’il puisse malgré tout avoir accès aux contrôles audio de base. C’est pourquoi nous ne supprimons l’UI par défaut que dans le contexte de notre script :

<script>
   var audioPlayer = document.getElementById("audioplayer"),
   audioTrack = document.getElementById("audiotrack"),
   playButton = document.createElement("button");
   playButton.type = "button";
   audioPlayer.appendChild(playButton);
   audioTrack.removeAttribute("controls");
</script>

Ajouté en bas de votre page HTML, ce script réduit effectivement notre audio player à un simple élément <button>. Pour l’instant, le bouton Play n'a pas encore de texte. Nous allons devoir permuter pas mal de texte dans nos boutons, c’est donc une bonne idée de mettre ce script à part dans une fonction :

function setText(el,text) {
    el.innerHTML = text;
}

Maintenant, nous pouvons assigner un texte à n’importe quel élément HTML aussi facilement que cela :

setText(playButton,"Play");

Ensuite, il faut que notre bouton puisse effectivement faire quelque chose :

playButton.addEventListener("click", player);
function player() {
  if (audioTrack.paused) {
    setText(playButton,"Pause");
    audioTrack.play();
  } else {
    setText(playButton,"Play");
    audioTrack.pause();
  }
}

Remarquez que nous n’essayons pas de séparer les fonctions pour Play et Stop, mais nous les pensons en termes d’activité du bouton.

Créer un bouton Mute

Nous devons également créer des contrôles de volume audio. Le plus simple d’entre eux est le bouton Mute, qui utilise un pattern assez similaire à celui du bouton Play/Pause :

var muteButton = document.createElement("button");
setText(muteButton,"Mute");
muteButton.type = "button";
audioPlayer.appendChild(muteButton);
muteButton.addEventListener("click", muter);
function muter() {
  if (audioTrack.volume == 0) {
  setText(this,"Mute");
  audioTrack.volume = 1;
  } else {
  setText(this,"Unmute");
  audioTrack.volume = 0;
  } 
}

Cette fonction est un peu crue : lorsque le son désactivé est réactivé, il est réglé automatiquement sur le niveau de volume maximum (dans les limites du système), mais pour l’instant nous accepterons cette faiblesse.

Créer le contrôle du volume

Ensuite, nous allons créer un curseur de volume plus précis. Le candidat évident à ce contrôle UI est un élément range :

volumeSlider = document.createElement("input");
volumeSlider.type = "range";

L’élément range va recevoir de nombreux attributs déterminés par notre JavaScript, ce que nous pourrions faire de la même façon que nous venons de fixer le type pour notre nouvel input... mais ce n’est pas parce que nous créons un prototype que nous ne pouvons pas le faire d’une manière plus pratique. Idéalement, au moins une partie de notre code sera utilisée dans notre version finale du media player, nous devons donc essayer dès à présent d’écrire un code plus efficace.

Malheureusement, il n’existe pas de méthode plurielle de setAttributes que nous puissions utiliser pour définir les valeurs d’attributs multiples simultanément. Cependant, nous pouvons créer une fonction simple pour le faire :

function setAttributes(el, attrs) {
  for(var key in attrs){
  el.setAttribute(key, attrs[key]);
  }
}

Nous pouvons maintenant indiquer les attributs du curseur en une ligne de code unique :

setAttributes(volumeSlider, { "type": "range", "min": "0", "max": "1", "step": "any", "value": "1" });

Remarquez que les valeurs minimum et maximum du curseur correspondent à celles de la fonction muter().

Ensuite, nous ajoutons un listener à l’input de range, le volume de la piste audio étant déterminé par la valeur du curseur dans une fonction anonyme :

volumeSlider.addEventListener("input", function(){ 
    audioTrack.volume = volumeSlider.value;
});

Ici, nous rencontrons notre premier problème sérieux : fonctionnellement, abaisser le curseur de volume à 0 est équivalent à cliquer sur Mute, par conséquent ce changement d’état devrait apparaître sur le bouton. Comment faire pour que cela se produise ?

Synchroniser les contrôles

Ma solution consiste à séparer la question du bouton, et à écouter le changement de volume dans l'élément <audio> lui-même :

audioTrack.addEventListener('volumechange', volumizer);
function volumizer() {
  if (audioTrack.volume == 0) {
      setText(muteButton,"Unmute");
  } else { 
      setText(muteButton,"Mute");
  }
}

Il nous reste un ajustement à faire. Lorsque la piste musicale s’achève, la musique doit revenir au point de départ et le bouton Play doit afficher Play, plutôt que Pause ou Stop :

audioTrack.addEventListener('ended', finish);
function finish() {
  audioTrack.currentTime = 0;
  setText(playButton,"Play");
}

Et voilà ! Tout le code, avec une légère amélioration de la fonction muter() est en bas de cette page. J’ajoute également un lien vers une version plus fignolée sur CodePen, celle que vous avez vue en tête de cet article. Dans les deux prochains articles, nous verrons comment réaliser les améliorations.

function player() {
  if (audioTrack.paused) {
    setText(this, "Stop");
    audioTrack.play();
  } else {
    setText(this,"Play");
    audioTrack.pause();
  }
}
function setText(el,text) {
    el.innerHTML = text;
}
function finish() {
  audioTrack.currentTime = 0;
  setText(playButton,"Play");
}
function volumizer() {
  if (audioTrack.volume == 0) {
      setText(muteButton,"Unmute");
  } else {
      setText(muteButton,"Mute");
  }
}
function muter() {
  if (audioTrack.volume == 0) {
    audioTrack.volume = restoreValue;
    volumeSlider.value = restoreValue;
  } else {
    audioTrack.volume = 0;
    restoreValue = volumeSlider.value;
    volumeSlider.value = 0;
  }
}
function setAttributes(el, attrs) {
    for(var key in attrs){
        el.setAttribute(key, attrs[key]);
    }
}
var audioPlayer = document.getElementById("audioplayer"),
audioTrack = document.getElementById("audiotrack"),
playButton = document.createElement("button"),
muteButton = document.createElement("button"),
volumeSlider = document.createElement("input");
setText(playButton, "Play");
setText(muteButton, "Mute");
setAttributes(playButton, { "type": "button" });
setAttributes(muteButton, { "type": "button" });
setAttributes(volumeSlider, { "type": "range", "min": "0", "max": "1", "step": "any", "value": "1" });
audioPlayer.appendChild(volumeSlider);
audioPlayer.appendChild(muteButton);
audioPlayer.appendChild(playButton);
audioTrack.removeAttribute("controls");
playButton.addEventListener("click", player, false);
muteButton.addEventListener("click", muter, false);
volumeSlider.addEventListener("input", function(){ 
    audioTrack.volume = volumeSlider.value;
    }, false);
audioTrack.addEventListener('volumechange', volumizer, false);
audioTrack.addEventListener('ended', finish, false);

See the Pen Simple HTML5 Audio Player In Pure JS & CSS by Dudley Storey (@dudleystorey) on CodePen.

Remarque : ce code suppose des conditions parfaites, une fois JavaScript chargé : que votre navigateur supporte HTML5 et les divers aspects de l’API que nous avons utilisée ici, et que la piste audio se charge immédiatement. Ce ne sera pas toujours vrai : Android 2 et versions antérieures n’est pas compatible avec event.ended pour l’audio. Il y a des moyens de contourner le problème et de nombreuses solutions de repli que vous pourriez ajouter, mais je ne me concentrerai pas là-dessus aujourd’hui.

Lire l'article suivant : Créer un player audio en HTML5, 3e partie : microdonnées.


Liste des articles de cette série :

Créer un player audio en HTML5, 1ère partie : fonctionnalités et design
Créer un player audio en HTML5, 2e partie : le prototype
Créer un player audio en HTML5, 3e partie : microdonnées
Créer un player audio en HTML5, 4e partie : (tba)


original paru le dans le blog de Dudley Storey, Demosthenes.info.

Sur l’auteur : est enseignant, auteur, artisan et cycliste, il vit à Calgary, dans l’État de l’Alberta au Canada. Passionné par le web et le développement (mobile) qu’il enseigne depuis 15 ans, il est l’auteur de Pro CSS3 Animation, et publie régulièrement dans son blog demosthenes.info des articles sur HTML, CSS et SVG. On peut le suivre sur Twitter ou Google+.

Traduit avec l’aimable autorisation de l’auteur.
Copyright Dudley Storey © 2015.