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:
Propiedades | Descripción |
---|---|
.autoplay | El audio se reproducirá automáticamente. OJO: Es muy probable que no funcione*. |
.controls | Muestra los controles (play, pausa, tiempo, etc...) del elemento multimedia. |
.loop | Una vez el audio llegue a su fin, volverá a empezar. |
.muted | El elemento multimedia está silenciado y no se escuchará. |
.defaultMuted | El 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 url
. De esta forma, tenemos muchas más propiedades, relacionadas con la reproducción multimedia:
Propiedades | Descripción |
---|---|
.src | Propiedad que devuelve la URL al archivo multimedia de audio. |
.volume | Volumen del audio, desde 0 (silencio) a 1 (máximo). Permite decimales. |
.paused | Indica si el audio está pausado (cualquier estado que no sea reproduciendo). |
.ended | Indica si el audio se ha terminado de reproducir. |
.currentTime | Número de segundos (con decimales) en el que se encuentra la reproducción. |
.duration | Duración total en segundos (con decimales) del audio. |
.playbackRate | Velocidad de reproducción, desde 0 hasta 4 . Velocidad normal: 1 . Muteado: 0 . |
.defaultPlaybackRate | El 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:
Propiedades | Valor | |
---|---|---|
Indica si el audio debe precargarse. | ||
.preload | auto (valor por defecto) metadata sólo deben precargarse los metadatos none no debe precargarse nada. | |
Indica en que estado está la red. | ||
.networkState | NETWORK_EMPTY (0) - No hay datos aúnNETWORK_IDLE (1) - No está descargando informaciónNETWORK_LOADING (2) - Está descargando informaciónNETWORK_NO_SOURCE (3) - No se encontró fuente .src | |
Indica el estado del recurso multimedia. | ||
.readyState | HAVE_NOTHING (0) - Sin informaciónHAVE_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. | |
.seeking | Indica 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 elmimetype
de un fichero de audio: por ejemplo, en el caso de un.mp3
seríaaudio/mp3
y en el caso de un.ogg
seríaaudio/ogg
. En el primer caso, Chrome nos devuelve elprobably
que indica que es muy probable que esté soportado, mientras que en el segundo caso devuelvemaybe
, 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étodos | Descripció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ón | Descripción |
---|---|
.pause | Se ha pausado y detenido la reproducción del recurso multimedia. |
.play | Se ha comenzado (o reanudado) la reproducción del recurso multimedia. |
.ended | Se ha llegado al final del recurso multimedia. |
.seeking | Ha comenzado la búsqueda de una posición de tiempo en un recurso multimedia. |
.seeked | Ha 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 cambios | Descripción |
---|---|
.ratechange | Se ha modificado la velocidad de reproducción del recurso multimedia. |
.durationchange | La duración del recurso multimedia ha cambiado. |
.timeupdate | El instante actual de tiempo de reproducción ha cambiado. Se dispara continuamente. |
.volumechange | El 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 carga | Descripción |
---|---|
.abort | La carga del recurso multimedia se ha detenido, pero no por un error. |
.error | La carga del recurso multimedia se ha detenido, resultado de un error. |
.suspend | Se suspende (intencionalmente) la carga de datos del recurso multimedia. |
.canplay | Se puede reproducir el recurso multimedia, pero habrá que esperar por «buffering». |
.canplaythrough | Se puede reproducir el recurso multimedia sin necesidad de esperar «buffering». |
.emptied | La carga del recurso se ha quedado vacía. Ejemplo: Después de un .load() . |
.loadstart | El navegador ha comenzado a cargar un recurso multimedia. |
.loadeddata | El navegador ha precargado el primer bloque de datos del recurso multimedia. |
.loadedmetadata | El navegador ha precargado los metadatos del recurso multimedia. |
.playing | Tras una falta de datos, el recurso multimedia vuelve a estar listo para reproducirse. |
.progress | Se dispara frecuentemente, cuando el navegador ha cargado dicho recurso. |
.waiting | La reproducción se ha detenido por ausencia (temporal) de datos. |
.stalled | El 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ía | Descripción | URL | Descripción |
---|---|---|---|
Howler.js | Librería para trabajar con audio de forma sencilla. | Howler.js | GitHub |
Tone.js | Framework de audio (DAW) para crear música interactiva. | Tone.js | GitHub |
Pizzicato | Librería para crear y manipular sonidos vía Web Audio API. | Pizzicato | GitHub |
WaveSurferJS | Visualización en forma de onda usando Web Audio / Canvas. | WaveSurfer | GitHub |
Web Audio DAW | Estación de trabajo de Audio Digital. Un «jQuery» de audio. | - | GitHub |
Blip | Librería ligera que usa Web Audio y lo simplifica. | BlipJS | GitHub |
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.