API de Audio Javascript

API multimedia para reproducir audio o video


Javascript proporciona una serie de API nativas para trabajar con archivos multimedia directamente desde el navegador. De esta forma, podemos permitir al usuario interactuar con recursos multimedia de forma dinámica, e incluso hacer multitud de interesantes aplicaciones que utilicen tanto archivos de audio como de video.

Aunque se puede trabajar con muchos otros tipos de formatos multimedia como archivos .mp4 (video) o archivos .ogg (audio vorbis), en este artículo trataremos archivos .mp3, ya que son los más populares en cuanto a archivos multimedia de audio. Muchas veces hablaremos de recursos multimedia, ya que igual que lo hacemos con un archivo de audio, se puede hacer con un archivo de video.

Crear audio

Un ejemplo básico para reproducir un archivo multimedia .mp3 desde nuestro navegador, podría ser uno de los siguientes:

Quizás la forma más sencilla de crear el audio, es hacerlo desde el HTML. Creando una etiqueta HTML <audio> con clase music que contenga la URL del fichero .mp3:

<audio class="music"
       src="https://manzdev.github.io/codevember2017/assets/eye-tiger.mp3">
</audio>

<script type="module">
  const music = document.querySelector(".music");
  music.play();
</script>

Luego, localizamos el audio buscándolo en el DOM con querySelector() y lo reproducimos llamando a su método play(). No obstante, hay otras formas de crear audios y reproducirlos, utilizando Javascript.

Observa que la constante music contiene una instancia del objeto Audio, al que se le pasa por parámetro la URL del archivo .mp3 que queremos inicializar. En lugar de una URL, también podríamos indicar simplemente el nombre de un archivo .mp3, con lo que el navegador buscaría dicho archivo en la misma ruta donde tenemos nuestro archivo .js con el código Javascript.

const url = "https://manzdev.github.io/codevember2017/assets/eye-tiger.mp3";
const music = new Audio(url);
music.play();

Posteriormente, ejecutamos la función .play() de la instancia music recién creada.

En este ejemplo, lo que hemos hecho realmente es crear una etiqueta HTML de audio igual que hicimos en el ejemplo HTML, sólo que usamos Javascript para indicarle el archivo de audio a inicializar, además de que esa etiqueta no reside «físicamente» en el documento HTML, si no que está en memoria, en la constante music.

En el siguiente ejemplo podemos ver un ejemplo análogo al anterior, pero en lugar de usar new Audio(), utilizamos el DOM de Javascript para crear la etiqueta <audio> en el HTML:

const audio = document.createElement("audio");
audio.preload = "auto";
audio.src = "https://manzdev.github.io/codevember2017/assets/eye-tiger.mp3";
audio.play();
document.body.append(audio);

La diferencia sobre el anterior, es que en esta última línea, de forma opcional hemos añadido la etiqueta <audio> creada al documento HTML en el que nos encontramos, justo antes de cerrar el </body>.

Si quieres más información sobre esto, mira el capítulo de trabajo en el DOM.

Propiedades

Una vez creado nuestro objeto de audio de cualquiera de las formas anteriores, ahora podemos acceder a él y acceder a sus propiedades, que nos permitirán realizar ciertas tareas.

Propiedades básicas

Al crear un objeto de audio mediante Javascript (que no es más que una etiqueta HTML), podemos utilizar la notación de objeto para crear propiedades que reflejarán el valor en atributos de la etiqueta HTML. De esta forma, podemos utilizar las siguientes propiedades, que son todas booleanas:

PropiedadesDescripción
.autoplayEl audio se reproducirá automáticamente. OJO: Es muy probable que no funcione*.
.controlsMuestra los controles (play, pausa, tiempo, etc...) del elemento multimedia.
.loopUna vez el audio llegue a su fin, volverá a empezar.
.mutedEl elemento multimedia está silenciado y no se escuchará.
.defaultMutedEl valor muted inicial por defecto, aunque muted se haya modificado posteriormente.

Un ejemplo de su uso sería el siguiente, donde vemos que podemos tanto obtener su valor como asignar un booleano para modificarlo:

const audio = new Audio("sound.mp3");
audio.loop = true;
audio.controls = true;
audio.play();

Desde 2017, Chrome, Firefox y otros navegadores establecieron un cambio de políticas con el atributo de reproducción automática autoplay. Para evitar molestos comportamientos de audio indeseado en páginas webs, por defecto la autoreproducción sólo funciona si el usuario ha interactuado antes en la página. Lo recomendable es sólo reproducir música o sonido si el usuario hace una acción específica (click de ratón o similar).

Propiedades de reproducción

Si quisieramos modificar nuestro objeto de Audio para indicarle un archivo multimedia diferente, sólo tendríamos que asignarle un diferente a la propiedad url. De esta forma, tenemos muchas más propiedades, relacionadas con la reproducción multimedia:

PropiedadesDescripción
.srcPropiedad que devuelve la URL al archivo multimedia de audio.
.volumeVolumen del audio, desde 0 (silencio) a 1 (máximo). Permite decimales.
.pausedIndica si el audio está pausado (cualquier estado que no sea reproduciendo).
.endedIndica si el audio se ha terminado de reproducir.
.currentTimeNúmero de segundos (con decimales) en el que se encuentra la reproducción.
.durationDuración total en segundos (con decimales) del audio.
.playbackRateVelocidad de reproducción, desde 0 hasta 4. Velocidad normal: 1. Muteado: 0.
.defaultPlaybackRateEl valor inicial de playbackRate, tras haberlo modificado.

Observa en el siguiente ejemplo que, .currentTime además de usarse para obtener el momento exacto en el que se encuentra la reproducción, también se puede utilizar para modificar ese momento. Por ejemplo, .currentTime = 0 se podría utilizar para inicializar el sonido:

const url = "https://manzdev.github.io/codevember2017/assets/eye-tiger.mp3";
const audio = new Audio(url);

audio.volume = 0.5;               // Volumen al 50%
console.log(audio.paused);        // true (no se está reproduciendo)
console.log(audio.currentTime);   // 0
console.log(audio.duration);      // 17.81551 (17 secs, 815.51 ms)
audio.currentTime = 5;            // Move to 5 secs
audio.play();                     // Starts audio from 5 sec

Propiedades de precarga

Cuando establecemos el atributo .src en un elemento de audio, el navegador automáticamente llama a la función .load() (ver más adelante) y se comienza a precargar el elemento de audio, dependiendo del valor que tenga la propiedad o atributo .preload. Veamos varias de las propiedades relacionadas con la precarga de un objeto de Audio:

PropiedadesValor
Indica si el audio debe precargarse.
.preloadauto (valor por defecto)
metadata sólo deben precargarse los metadatos
none no debe precargarse nada.
Indica en que estado está la red.
.networkStateNETWORK_EMPTY (0) - No hay datos aún
NETWORK_IDLE (1) - No está descargando información
NETWORK_LOADING (2) - Está descargando información
NETWORK_NO_SOURCE (3) - No se encontró fuente .src
Indica el estado del recurso multimedia.
.readyStateHAVE_NOTHING (0) - Sin información
HAVE_METADATA (1) - Hay metadatos, sólo búsqueda.
HAVE_CURRENT_DATA (2) - Datos suficientes para punto actual.
HAVE_FUTURE_DATA (3) - Datos suficientes para saltos cercanos.
HAVE_ENOUGH_DATA (4) - Datos suficientes para saltos sin cortes.
.seekingIndica true si está en proceso de moverse a un nuevo instante (buscando).

Mientras que el valor preload puede indicarse como un atributo HTML, el resto de propiedades no se pueden indicar, y son exclusivas de la API de Javascript. Generalmente suelen utilizarse para saber el estado de carga de un elemento de audio o información relacionada.

Métodos o funciones de audio

Los métodos que más nos pueden interesar en la API de Audio de Javascript son los de .play() y .pause(), ya que son los que comienzan a reproducir (o continuan una reproducción pausada previamente) y detienen una reproducción respectivamente.

Quizás, el método más extraño sea .canPlayType(mimetype), el cuál se puede llamar, indicando como parámetro el mimetype de un fichero de audio: por ejemplo, en el caso de un .mp3 sería audio/mp3 y en el caso de un .ogg sería audio/ogg. En el primer caso, Chrome nos devuelve el probably que indica que es muy probable que esté soportado, mientras que en el segundo caso devuelve maybe, con el que indica que es menos probable, y depende de otros factores (sistema operativo, etc...).

Por otro lado, tenemos el método .load() que se encarga de inicializar un recurso y comenzar a procesarlo, dependiendo del valor actual del atributo preload que hablamos antes. El método .load() se llama automágicamente al cambiar el atributo o propiedad .src.

MétodosDescripción
.canPlayType(mimetype)Indica si el tipo MIME indicado está soportado (probably) o no (maybe).
.load()Inicializa el recurso multimedia para prepararlo para reproducir.
.play()Comienza a reproducir (o reanuda) el audio en cuestión.
.pause()Pausa el sonido, con la posibilidad de reanudarlo.

Por último, tenemos los métodos .play() (reproducir un audio) y .pause() (detener un audio), que tienen algunas puntualizaciones:

const audio = new Audio("audio.mp3");

audio.play();          // Comienza a reproducir el audio
audio.pause();         // Pausa el audio
audio.play();          // Continua el audio por donde fue pausado

audio.pause();         // Vuelve a pausar
audio.currentTime = 0; // Coloca la reproducción en el segundo 0 (inicio)
audio.play();          // Reproduce desde el inicio

Es importante mencionar que el método .play() devuelve una promesa que se resuelve cuando el audio está descargado y ha comenzado a reproducirse. Ten en cuenta que dicho audio está alojado en una página web y puede no estar disponible en el momento de reproducir el audio, es por esto que devuelve una promesa:

const audio = new Audio("audio.mp3");

audio.play()
  .then(() => console.log("Comenzó la reproducción..."));

Sin embargo, al ser una acción auditiva, que no requiere visualización explícita, muchas veces no es necesario controlar la promesa y se puede ejecutar el .play() directamente.

Eventos de audio

Una de las partes más interesantes de la API multimedia es la posibilidad de jugar con eventos multimedia relacionados con objetos de audio. Recuerda que los eventos en Javascript son acciones muy específicas que suceden en momentos concretos de la vida de nuestra aplicación o web:

  • Cuando el usuario hace click...
  • Cuando el usuario hace scroll...
  • Cuando el usuario pausa un sonido en la barra de control...

De esta forma, tenemos múltiples tipos de eventos que podemos utilizar.

En este primer bloque encontraremos los eventos que ocurren en momentos comunes de la reproducción de un recurso multimedia, como cuando comenzamos a reproducirlo, lo detenemos o vamos a un momento específico de su duración:

Eventos de reproducciónDescripción
.pauseSe ha pausado y detenido la reproducción del recurso multimedia.
.playSe ha comenzado (o reanudado) la reproducción del recurso multimedia.
.endedSe ha llegado al final del recurso multimedia.
.seekingHa comenzado la búsqueda de una posición de tiempo en un recurso multimedia.
.seekedHa terminado la búsqueda de una posición de tiempo en un recurso multimedia.

Veamos un ejemplo básico de uso de algunos de estos eventos:

const audio = new Audio("audio.mp3");

audio.addEventListener("play", () => {
  console.log("Se ha comenzado/reanudado la reproducción");
});

audio.addEventListener("pause", () => {
  console.log("Se ha pausado la reproducción");
});

Por otro lado, también podemos ejecutar una lógica específica cuando suceden ciertos eventos relacionados con el cambio de alguno de sus parámetros iniciales, como la velocidad de reproducción o el segundo actual de reproducción:

Eventos de cambiosDescripción
.ratechangeSe ha modificado la velocidad de reproducción del recurso multimedia.
.durationchangeLa duración del recurso multimedia ha cambiado.
.timeupdateEl instante actual de tiempo de reproducción ha cambiado. Se dispara continuamente.
.volumechangeEl volumen del recurso multimedia ha sido modificado.

Observa en el siguiente ejemplo, que el evento timeupdate se ejecutará varias veces en el mismo segundo, no una sola vez por segundo como quizás se imagina inicialmente. Esto ocurre porque la precisión de la actualización de tiempo, afecta a milisegundos, por lo que se ejecuta varias veces en el mismo segundo:

const audio = new Audio("audio.mp3");

audio.addEventListener("timeupdate", () => {
  console.log("Current second: ", Number.parseInt(audio.currentTime));
});

Por último, tenemos múltiples eventos relacionados con la carga o precarga de los recursos multimedia, sus metadatos o el proceso de «buffering» donde la reproducción no se puede realizar porque aún no se ha descargado la suficiente cantidad de datos para reproducir:

Eventos de cargaDescripción
.abortLa carga del recurso multimedia se ha detenido, pero no por un error.
.errorLa carga del recurso multimedia se ha detenido, resultado de un error.
.suspendSe suspende (intencionalmente) la carga de datos del recurso multimedia.
.canplaySe puede reproducir el recurso multimedia, pero habrá que esperar por «buffering».
.canplaythroughSe puede reproducir el recurso multimedia sin necesidad de esperar «buffering».
.emptiedLa carga del recurso se ha quedado vacía. Ejemplo: Después de un .load().
.loadstartEl navegador ha comenzado a cargar un recurso multimedia.
.loadeddataEl navegador ha precargado el primer bloque de datos del recurso multimedia.
.loadedmetadataEl navegador ha precargado los metadatos del recurso multimedia.
.playingTras una falta de datos, el recurso multimedia vuelve a estar listo para reproducirse.
.progressSe dispara frecuentemente, cuando el navegador ha cargado dicho recurso.
.waitingLa reproducción se ha detenido por ausencia (temporal) de datos.
.stalledEl navegador intenta obtener datos de un recurso pero no los recibe.

Muchos de estos eventos nos permiten personalizar como actuará nuestra aplicación o web respecto a lo que haya sucedido.

Cuidado: No confundir el evento .onplay con el evento .onplaying. El segundo es el que ocurre cuando ya podemos reproducir un audio porque estaba en proceso de «buffering», mientras que el primero es el que se dispara cuando comenzamos o continuamos una reproducción multimedia.

Librerías de terceros

Es posible que en algunos casos, la API multimedia nativa de Javascript se nos quede corta. En ese caso, existen algunas librerías interesantes que pueden servirnos para simplificar nuestro código y realizar acciones más concretas.

Por ejemplo, Howler.js es una excelente librería para cuando la API nativa se nos queda corta o necesitamos algo un poco más potente:

LibreríaDescripciónURLDescripción
Howler.jsLibrería para trabajar con audio de forma sencilla.Howler.jsGitHub
Tone.jsFramework de audio (DAW) para crear música interactiva.Tone.jsGitHub
PizzicatoLibrería para crear y manipular sonidos vía Web Audio API.PizzicatoGitHub
WaveSurferJSVisualización en forma de onda usando Web Audio / Canvas.WaveSurferGitHub
Web Audio DAWEstación de trabajo de Audio Digital. Un «jQuery» de audio.-GitHub
BlipLibrería ligera que usa Web Audio y lo simplifica.BlipJSGitHub

Otras librerías como Tone.js o Pizzicato nos permiten centrarnos en la generación de sonidos utilizando la API Web Audio y/o utilizando sonidos externos.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev