Libere el poder de <audio> HTML5

Por Giorgio Sardo

Libere el poder de <audio> HTML5

Los sonidos constituyen la base de nuestra vida. Hoy en día, el elemento <audio> HTML5 le da a los desarrolladores Web la posibilidad de incrustar sonidos en sus aplicaciones. La flexibilidad del control a la par de la integración con el resto de la plataforma permite varios escenarios, desde los más sencillos efectos de sonido y audio de fondo hasta experiencias de juego y motores de audio más sofisticados..

Este blog explora algunas de las mejores prácticas para la utilización de la etiqueta <audio> en las aplicaciones Web, e incluye consejos útiles de sitios del mundo real.

Agregando un elemento de audio a su página

El primer paso consiste en agregar el elemento de audio a su página. Para ello, puede declarar una etiqueta <audio> en el código de marcado, al crear instancias de un nuevo elemento de audio en el código de JavaScript, o mediante la incorporación del flujo de audio en la página:


<audio src="audio/sample.mp3" autoplay>

</audio>


var audio = document.createElement("audio");

if (audio != null && audio.canPlayType && audio.canPlayType("audio/mpeg"))

{

	audio.src = "audio/sample.mp3";

	audio.play();

}


<audio src="data:audio/mpeg,ID3%02%00%00%00%00%..." autoplay>

</audio>

El primer enfoque le permite iniciar los componentes de audio durante la carga de la página. El segundo enfoque le ofrece más flexibilidad y una mejor gestión del flujo de la red, ya que aplaza la carga del clip de audio a un momento específico durante el ciclo de vida de la aplicación. El tercer criterio (menos recomendable) consiste en incrustar los archivos de audio como data-uri en la página, reduciendo el número de solicitudes al servidor.
Tenga en cuenta que puede reproducir un elemento de audio generado por JavaScript incluso si no se agrega en realidad al árbol DOM (como en el fragmento de código anterior). Sin embargo agregar el elemento de audio a la página te permitirá mostrar la barra de control predeterminada.

Aunque no se incluya en esta publicación, puede soportar más de un formato de archivo de audio. Además, si va a hospedar los archivos de audio en su servidor, no se olvide de registrar el tipo MIME para archivos mp3 ("audio/mpeg") del lado del servidor. Aquí, por ejemplo, está la configuración de Internet Information Services (IIS).

La carga del audio antes de reproducir

Una vez que tiene el elemento de audio, puede elegir la mejor estrategia de precarga. La especificación HTML5 <audio> describe una propiedad de precarga con tres posibles valores:

  • "none": le da al agente usuario la pauta de que el autor no espera que el usuario necesite el recurso de medio, o que el servidor quiere minimizar el tráfico innecesario.
    Si el escenario es un blog podcast con un archivo de audio para cada publicación, esta opción funciona muy bien, ya que reduce el ancho de banda de carga inicial. Una vez que el usuario reproduce el archivo (ya sea a través de los controles visuales por omisión o los métodos de carga de JavaScript load() o play()), el navegador empezará a buscar al flujo de audio.
  • "metadata": ": le da al agente usuario la pauta de que el autor no espera que el usuario necesite el recurso de medio, pero que obtener los metadatos (dimensiones, duración, etc.) del recurso sea razonable.
    Esta es la opción recomendada si va a crear un control de reproductor de audio y necesita información básica sobre el clip de audio, pero no es necesario reproducirlo aún.
  • "auto": le da la pauta al agente usuario de que éste puede poner las necesidades del usuario en primer lugar sin riesgo alguno para el servidor, hasta que se descargue todo el recurso.
    Si usted está programando un juego, este enfoque es probablemente el mejor, por lo que le permite precargar todos los clips de audio antes de iniciar realmente la experiencia de juego.

Tenga en cuenta que cuando se establece la propiedad src del elemento de audio mediante programación, el navegador establece la propiedad de precarga a "auto", a menos que se indique lo contrario. Por esta razón, si su escenario necesita un valor diferente, asegúrese de que lo especifique en una línea de código antes de configurar el src.
Usted puede obtener una vista previa del impacto sobre la red de estas tres opciones al ejecutar esta página utilizando las herramientas del desarrollador F12 (pestaña Red). Para depurar puede simular llamadas nuevas y desactivar la caché local mediante el control de "Siempre actualizar desde el servidor".

preload=none:

preload=metadata:

preload=auto:

Mientras que esta propiedad es ideal para la fase de inicio, es posible que también necesite saber cuando ha descargado realmente el navegador el clip de audio y está listo para reproducirlo. Usted puede obtener esta información al escuchar el evento "canplaythrough"; este evento es llamado por el Agente de Usuario una vez que estima si la reproducción se inicia ahora, los recursos de comunicación podrían ser proporcionados con la tasa actual de reproducción hasta el final sin tener que parar por más buffering.


var audio = document.createElement("audio");

audio.src = "audio/sample.mp3";

audio.addEventListener("canplaythrough", function () {

	alert('The file is loaded and ready to play!');

}, false);

Circuitos

Otra necesidad frecuente para escenarios con audio es la capacidad de hacer que un clip de sonido se reproduzca como bucle. Con la <audio>, HTML5, se puede hacer esto usando la propiedad "loop"; esta opción reproducirá su clip en un bucle infinito, o hasta que el usuario o la aplicación active el control de pausa() en el audio.


<audio src="audio/sample.mp3" autoplay loop>

</audio>

Otra forma de reproducir en bucle archivo de audio es mediante programación hacer una llamada al método play() cuando el clip de audio finalice; ello permitirá que usted pueda en algún punto administrar el tiempo de espera entre uno y otro bucle.


var audio = document.createElement("audio");

audio.src = "piano/3C.mp3";

audio.addEventListener('ended', function () {

	// Wait 500 milliseconds before next loop

	setTimeout(function () { audio.play(); }, 500);

}, false);

audio.play();

Tenga en cuenta que cualquier llamada a play() ejecutada sobre el elemento de audio antes de que el sonido en realidad haya terminado no tendrá ningún efecto. Si usted está interesado en "cancel and restart" el sonido actual, necesitará restablecer la propiedad CurrentTime del reloj.


var audio = null;

audio = document.createElement("audio");

audio.src = "piano/3C.mp3";

audio.addEventListener('ended', function () {

	audio.play();

}, false);

function play() {

	audio.play();

}

function restart() {

	audio.currentTime = 0;

	audio.play();

}

Etiquetas de audio múltiples

Si su escenario requiere que el mismo archivo de audio se repita varias veces en forma concurrente (es decir, con superposición de sonidos), puede conseguir este resultado si se crean varias etiquetas de audio que apunten en el mismo archivo. Evidentemente el mismo enfoque también funciona si está usando diferentes archivos de audio al mismo tiempo. Como explicamos anteriormente en esta publicación, puede agregarlos mediante programación o por instancias en el marcado.

El siguiente fragmento de código muestra cómo cargar y reproducir múltiples archivos de audio utilizando marcado. Todas las muestras de audio tienen la misma longitud; al final de la ejecución, se producirá un bucle empezando desde el principio. Al mismo tiempo que las reproduce en Internet Explorer 9 se puede observar que se sincronizan automáticamente a través de diversos bucles. Notará que la combinación de estos 5 sonidos se reproducirán como el archivo de audio utilizado en el ejemplo anterior ( "sample.mp3 " ).


<body>

	<audio src="audio/Bass.mp3" autoplay loop>

	</audio>

	<audio src="audio/Drum.mp3" autoplay loop>

	</audio>

	<audio src="audio/Crunch.mp3" autoplay loop>

	</audio>

	<audio src="audio/Guitar.mp3" autoplay loop>

	</audio>

	<audio src="audio/Pizzicato.mp3" autoplay loop>

	</audio>

</body>

Si bien este enfoque es muy simple y directo, en la mayoría de los escenarios los desarrolladores prefieren crear los clips de audio mediante programación. El siguiente fragmento de código muestra cómo agregar 3 clips de audio dinámicamente usando código. Conforme los reproduces juntos, ¡recibirás el acorde de Do Mayor!


AddNote("3C");

AddNote("3E");

AddNote("3G");

function AddNote(name) {

	var audio = document.createElement("audio");

	audio.src = "piano/" + name + ".mp3";

	audio.autoplay = true;

}

¡Este patrón de código funciona en cualquier navegador y le permitirá construir escenarios muy atractivos!

Es importante tener en cuenta que a medida que su juego o aplicación se vuelve más compleja puede llegar a alcanzar dos límites: el número de elementos de audio que puede precargar en la misma página y el número de elementos de audio se pueden reproducir al mismo tiempo.

Estos números dependen del navegador y las capacidades de su equipo. Basado en mi experiencia, Internet Explorer 9 puede manejar decenas de elementos de audio en forma concurrente sin problemas. Otros navegadores no lo hacen tan bien, se puede encontrar con evidentes retrasos y distorsiones conforme toca varios archivos en un bucle.

Las estrategias de sincronización

Dependiendo de las características de la red, tenga siempre en cuenta el retraso que implica el proceso entre añadir la etiqueta, obtener el contenido y estar listo para la reproducción. En específico, cuando se manejan múltiples archivos, cada archivo podría estar listo para reproducción antes o después. Aquí, por ejemplo, tenemos una captura con los 3 archivos utilizados previamente, cargados desde el mismo host.

Como se puede ver en la columna de los Cronometrajes, los diferentes archivos pueden estar listos en un momento diferente.

Una estrategia muy común de sincronización es la de precargar todos los archivos primero. Una vez que todo está listo, puede iterar rápidamente a través de un bucle y comenzar a reproducir.


var audios = [];

var loading = 0;

AddNote("2C");

AddNote("2E");

AddNote("2G");

AddNote("3C");

AddNote("3E");

AddNote("3G");

AddNote("4C");

function AddNote(name) {

	loading++;

	var audio = document.createElement("audio");

	audio.loop = true;

	audio.addEventListener("canplaythrough", function () {

		loading--;

		if (loading == 0) // All files are preloaded

			StartPlayingAll();

	}, false);

	audio.src = "piano/" + name + ".mp3";

	audios.push(audio);

}

function StartPlayingAll() {

	for (var i = 0; i < audios.length; i++)

		audios[i].play();

}

¡Hagamos todo juntos ahora! La siguiente demostración simula un piano Frère Jacques (también conocido como el Hermano John, el Hermano Pedro…o Fra Martino). La página inicia por recoger todas las notas, mostrando el progreso conforme se precargan en el cliente. Una vez que todo está listo, la canción empieza a reproducirse en un bucle.

Audio en sitios reales

Ahora que hemos visto los patrones comunes para manejar múltiples archivos de audio, me gustaría destacar algunos sitios Web como ejemplos de mejores prácticas que usan la etiqueta <audio>.

Pirates Love Daises: www.pirateslovedaisies.com

En otro blog post hablé de Pirates Love Daises, un imponente juego en HTML5 construido por Grant Skinner. Además del gran juego y atractivos efectos visuales, el equipo de Grant también desarrolló una sofisticada biblioteca de audio que reproduce varias muestras de audio en todo el juego. La lógica principal está encapsulada en la clase AudioManager. Como se indicó anteriormente, antes de comenzar el juego el sitio precarga todos los clips de audio y muestra el progreso acumulativo en la pantalla de carga inicial. El sitio también toma en cuenta el caso de interrupciones en la de red o errores que se produjeron mientras se descargaba un archivo de audio.


addAudioChannel:function(b,a,f){

	var h=document.createElement("audio");

	if(f!=true){

		this.currAsset=h;

		this.timeoutId=setTimeout($.proxy(this,"handleAudioTimeout"),e.AUDIO_TIMEOUT);

		h.addEventListener("canplaythrough",$.proxy(this,"handleAudioComplete"),false);

		h.addEventListener("error",$.proxy(this,"handleAudioError"),false)

	}

	h.setAttribute("id",a);

	h.setAttribute("preload","auto");

	$("").attr("src",b).appendTo(h);

	$("").attr("src",b.split(".mp3")[0]+".ogg").appendTo(h);

	document.body.appendChild(h)

}

,handleAudioComplete:function(b){

	if(LoadedAssets.getAsset(b.target.id)!=true){

		LoadedAssets.addAsset(b.target.id,true);

		clearTimeout(this.timeoutId);

		this.calculatePercentLoaded(true)

	}

}

,handleAudioError:function(b){

	trace("Error Loading Audio:",b.target.id);

	LoadedAssets.addAsset(b.target.id,true);

	clearTimeout(this.timeoutId);

	this.calculatePercentLoaded(true)

}

,handleAudioTimeout:function(){

	trace("Audio Timed Out:",this.currAsset.id);

	LoadedAssets.addAsset(this.currAsset.id,true);

	this.calculatePercentLoaded(true)

}

Grant está actualmente trabajando en un proyecto de biblioteca de sonidos proyecto que permitirá a los desarrolladores utilizar su lógica del motor de sonido con cualquier otra aplicación. ¡Lo esperamos con ancias!

Fuegos Artificiales (por Mike Tompkins): www.beautyoftheweb.com/firework

El demo de Firework es particularmente interesante, ya que le permite interactuar con varias pistas de audio al mismo tiempo, cambiando dinámicamente el volumen de cada pista. Por otra parte, conforme interactúa con los canales de audio, la interfase reacciona dinámicamente a diferentes entradas o configuraciones.

Esta vez las etiquetas de audio se han declarado en el marcado HTML (sólo hay 6 pistas). El progreso se monitorea mediante programación por medio del evento canplaythrough. Una vez que todos los archivos de audio están listos para reproducirse, un bucle pasa a la lista y empieza a sonar.


video.addEventListener('canplaythrough', onCanPlayAudio, false);

for (var i = 0; i < 5; i++) {

	var aud = document.getElementById("aud" + i);

	targetVolumes.push(0);

	aud.volume = 0;

	audioTags.push({

		"tag": aud,

		"ready": false

	});

	aud.addEventListener('canplaythrough', onCanPlayAudio, false);

}

// Set audio/video tracks

document.getElementById("tompkins").src = MediaHelper.GetVideoUrl("Firework_3");

for (var i = 0; i < audioTracks.length; i++) {

	document.getElementById("aud" + i).src = MediaHelper.GetAudioUrl(audioTracks[i]);

}

Los desarrolladores también decidieron iniciar con el volumen en 0 para aumentarlo dinámicamente a 1 tan pronto como la experiencia está lista para reproducirse. Dependiendo de la calidad de su tarjeta de sonido y los controladores, este pequeño truco reduce la probabilidad de escuchar un ruido "knock" inicial al principio del audio.

BeatKeep: www.beatkeep.net

El último escenario es probablemente el más complicado de los ejemplos que se muestran aquí. En este ejemplo, usted puede crear sus propias canciones usando una beat machine y tocar varios clips de audio en un bucle. En esta aplicación, es fundamental tener una perfecta sincronización de los canales de audio y un sistema de buffer ágil para cargar varios clips.

La beat machine le da un control completo sobre el tiempo y el compás; usando sofisticados modelos de lógica de temporizador y modelo unión, ¡el resultado final es una muy buena experiencia!

Conclusiones

Les sugiero que prueben todas las muestras y las aplicaciones en este post usando Internet Explorer 9 u otros exploradores y háganos saber cuál fue su experiencia. Puede descargar todo el código de ejemplo utilizado en este artículo aquí.

Si desea conocer más acerca de los controles de audio y video, le recomiendo que vea la sesión de media hora de MIX " 5 cosas que usted necesita saber para empezar a usar <audio> y <video> Hoy" o lea estos artículos interesantes en MSDN.

Gracias a DoubleDominant para los clips de audio utilizados en este blog y a Grant Skinner y Archetype por sus increíbles experiencias HTML5.

—Giorgio Sardo | Sr. Technical Evangelist – HTML5 e Internet Explorer

Deje un comentario...


Videos presentados

Otros recursos

Recursos HTML5 recientes

Temas de HTML5 en Slashdot

Webcasts presentados