Manejando audio (y vídeo) con HTML5

2
16743

Pequeños experimentos para probar cómo HTML5 permite manejar audio y vídeo en el navegador, añadir subtítulos en distintos idiomas y cómo, mediante JavaScript y las nuevas WebAPIs, se puede capturar el stream del micro y de la webcam.

Índice de contenidos

1. Introducción

En el cajón de las cosas que me quedan por aprender lleva mucho tiempo dando vueltas el tema del manejo de la webcam y micrófono desde el navegador, jugar con el text to speech y voice to text. La única forma de aprender es hacer pruebas y trastear en mi propio laboratorio virtual. Este post nace fruto de esa experimentación, y por eso surge este artículo, para compartir con el lector los resultados obtenidos.

Antes de HTML5 sólo se podía utilizar audio y vídeo en el navegador mediante algún tipo de plugin. Y flash era lo más utilizado para este fin. Pero eso tenía más contras que pros: el navegador requería tener instalado el software de Adobe, que no venía de serie en el browser y que no siempre ha demostrado ser seguro a lo largo de sus distintas versiones. Al final ese plugin ha caído en desgracia y cada vez su penetración en el sector es menor.

flash_en_gg_trends

Pero a la vez que Flash iba perdiendo protagonismo, han aparecido una serie de estándares que han venido al rescate, facilitando de forma natural la manipulación de audio y vídeo en los navegadores, a través de HTML5 y las nuevas WebAPIs.

Y en eso versa este artículo que se divide en dos grandes bloques:

  • el primero, trata de ver como mostrar audio y vídeo en la web, introduciendo subtítulos en distintos idiomas, y cómo capturar el stream de la webcam y el micrófono
  • el segundo trata de reconocimiento de voz, dictado, navegación mediante comandos de voz, y la operación inversa, que sería dado un texto, la correspondiente síntesis de voz.

2. Etiqueta <audio> y <video> de HTML

HTML5 introduce dos nuevas etiquetas <audio> y <video>. Me centraré en el primero, pues es el medio para conseguir el fin, siendo el objeto principal de estudio de este artículo el reconocimiento de voz y viceversa.

Como en tantas cosas, los distintos navegadores no se ponían de acuerdo en qué formatos de audio soportar. Hoy la mayoría soportan el formato ogg o mp3, siendo lo normal que soporten ambos, por lo que es conveniente proveerlos para que el browser utilice el primero que le resulte compatible.

<audio controls>
  <source src="ejemplo.mp3" type="audio/mpeg" />
  <source src="ejemplo.ogg" type="audio/ogg" />
  <p>Your user agent does not support the HTML5 Audio element.</p>
</audio>

Ver ejemplo 1: Sample Audio HTML Tag

Si tienes más interés, puedes consultar la lista de los formatos soportados por los distintos navegadores.

Algunos de los atributos que soporta la etiqueta <audio> son:

  • controls, que nos permite una representación gráfica de un reproductor, con sus correspondientes controles de pausa, play, volumen y una línea de tiempo.
  • autoplay, si se desea que empiece a reproducirse cuando se haya cargado el DOM.
  • preload que puede tomar alguno de los siguientes valores [«none», «metadata», «auto»], para precargarlo. Con metadata sólo se cargarían los metadatos (info, duración del fichero, etc…)
  • loop: para que se repita una y otra vez
  • mediagroup: para agrupar y hacer listas de reproducción.

Y hay numerosos eventos y propiedades vinculados a esta etiqueta que nos permiten jugar, siendo los siguientes los más comunes.

	var audio = document.getElementById('audio');

	function play(){
	  audio.play();
	}

	function pause(){
	  if (audio.paused){
	    audio.play();
	  }else{
	    audio.pause();
	  }
	}

	function stop(){
	  audio.pause();
	  audio.currentTime = 0;
	}

	function turnUpVolume(){
	  if (audio.volume<0.9){
	    audio.volume+=0.1;
	  }
	}

	function turnDownVolume(){
	  if (audio.volume>0.1){
	    audio.volume-=0.1;
	  }
	}

Ver ejemplo 2: Sample Audio Events

3. ¿Y cómo ponemos subtítulos?

Para esto tenemos la etiqueta <track>, que se puede usar en combinación tanto con la etiqueta <audio> como con la etiqueta <video>.

  <audio controls>
    <source src="ejemplo.mp3" type="audio/mpeg" />
    <track kind="subtitles" label="Subtítulos en español" src="subtitles_es.vtt" srclang="es" default />
    <track kind="subtitles" label="English subtitles" src="subtitles_en.vtt" srclang="en" />
    <track kind="subtitles" label="Deutsche Untertitel" src="subtitles_de.vtt" srclang="de" />
    <p>Your user agent does not support the HTML5 Audio element.</p>
  </audio>

Esta etiqueta se puede usar para diversas finalidades que se pueden definir en el atributo kind:

  • captions
  • chapters
  • descriptions
  • metadata
  • subtitles

Esto nos puede dar mucho juego para poner subtítulos en nuestros vídeos o audios. Lo bueno es que se puede facilitar traducciones a distintos idiomas para un mismo audio (o vídeo).

Estos ficheros utilizan un estándar denominado WebVTT que tiene un formato de texto plano muy sencillo: comienza con la palabra WEBVTT y sigue con una lista de cues. Un CUE es el mínimo grupo de información que está formado por: un identificador (opcional), por un rango de tiempo y el texto a mostrar.

Por ejemplo:

WEBVTT

00:00:00.000 --> 00:00:05.170
Bienvenidos a este curso de seguridad web

00:00:06.010 --> 00:00:08.870
En Autentia nos encanta compartir lo que…

00:00:08.920 --> 00:00:11.580
…aprendemos con la comunidad

00:00:12.680 --> 00:00:14.730
¡¡¡Venga. Vamos al lío!!!

El formato de este fichero es ciertamente melindroso. En https://quuz.org/webvtt/ validan si el WebVTT que estamos generando es válido, si los tiempos son secuenciales y no se solapa nada. Muy útil.

Jugando con la posibilidad de poner subtítulos, y preparando un ejemplo para esto, me he tropezado con algún que otro inconveniente:

  • crossdomain: video/audio, vtt y html deben de compartir dominio y, si no, usar CORS para remediar este problema.
  • si se usa la etiqueta <audio>, Chrome no muestra los subtítulos, ya que no tiene “espacio” donde mostrarlos en el componente del reproductor de audio. Tendríamos que leer los CUEs mediante JavaScript, que se puede, y ponerlos en un <div> fuera del reproductor de audio. Sin embargo, si cambiamos la etiqueta por <video>, nos reproduce el audio y los subtítulos.
  • Si los subtítulos aparecen desde el segundo 0 se muestran en la imagen de previsualización del vídeo (antes de darle al “play”). Así que es mejor que aparezcan unos milisegundos después.

En el siguiente ejemplo, he subtitulado el famoso discurso de Martin Luther King Jr., “I have got a dream”, para consolidar lo aprendido sobre los ficheros WebVTT.

Ver ejemplo 3: Subtitulando “I have got a dream”, de Martin Luther King

4. Controlando la webcam y el micrófono

Ya sabemos reproducir audio y vídeo en nuestras páginas y aplicaciones web pero ¿y cómo capturamos fotos, un vídeo o nuestra voz? HTML nos da acceso al micrófono y a la webcam mediante un método del objeto navigator llamado getUserMedia().

Lo primero es independizar la sintaxis del motor del navegador, ya que aún hay alguno que no tiene el método getUserMedia e implementa su propia versión con prefijo:

navigator.getUserMedia = navigator.getUserMedia ||
                         navigator.mozGetUserMedia ||
                         navigator.webkitGetUserMedia ||
                         navigator.msGetUserMedia;

Luego indicamos si queremos capturar vídeo, audio o ambas cosas. En el ejemplo para ilustrar este ejercicio, en un primer momento capturaba sonido e imagen, y posteriormente los reproducía en una página web. Esto producía el lógico e indeseable acoplamiento del sonido, al escucharse por los altavoces lo mismo que se capturaba por el micrófono.

navigator.getUserMedia({video: true, audio: false}, onSuccess, onError);

function onSuccess(streamVideo) {
    var videoProvider;

    if (window.URL) {
        videoProvider = window.URL.createObjectURL(streamVideo);
    } else {
        videoProvider = streamVideo;
    }

    myVideo.src = videoProvider;
    myVideo.play();

    myButton.value = "stop";
}

function onError(error) {
    console.log("getUserMedia() no longer works on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.", error);
}

Ver ejemplo 4: Manage the webcam and micro

Si todo ha ido bien, el navegador nos habrá pedido permiso para poder capturar el vídeo a través de la webcam. Con window.URL.createObjectURL(streamVideo) se crea un objeto de tipo Blob o File que consume recursos, que no se liberarán hasta que se cierre la página. Puedes descargarlo cuando ya no se utilice llamando a revokeObjectURL.

Nota: ambos métodos forman parte de la nueva File API del W3C, que veremos en otro próximo artículo.

Con esto hemos capturado el stream de audio y de vídeo, y se lo enchufamos al source de nuestro componente pero, de esta forma, estamos confinados a nuestra aplicación web. Una pregunta lógica sería ¿se pueden hacer más cosas con esto? ¿se puede grabar? ¿se puede enviar al servidor o a otro dispositivo?

En principio, parece que hay una especificación del W3C, aún en borrador, que propone usar el propio elemento file con el atributo accept.

Por ejemplo, para tomar una foto de la cámara y enviarla sería:

<input type="file" accept="image/*;capture=camera">

Mientras que para grabar sonido o vídeo sería:

<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">

La especificación que se está encargando de esto es: https://dev.w3.org/2009/dap/camera/. Os recomiendo echar un vistazo a los ejemplos, donde hay uno que explica cómo se haría con AJAX.

Ya sabemos capturar el sonido en bruto del micrófono pero ¿y si lo que queremos es grabar dicho sonido en un formato comprimido en tiempo real en el navegador? Hay un proyecto muy interesante sobre este tema que podéis encontrar en:

http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/

Por un lado hacen uso de la librería recorder.js para grabar el sonido y, por otro lado, han hecho una versión en JavaScript de la librería Lame MP3 encoder, libmp3lame.js, para comprimir a MP3 en tiempo real.

Si lo que deseamos es hacer videoconferencia sobre el navegador habría que recurrir a RTCPeerConnection y RTCDataChannel, pero eso lo dejamos para un posible POST más adelante sobre la WebRTC API.

En estos últimos puntos hemos pasado rápido, de puntillas, indicando una serie de enlaces donde averiguar más información, pero sin profundizar, y es que estos experimentos tienen enjundia suficiente como para tratarlos como una entidad propia y separada.

Y ahora retomamos nuestro objetivo inicial de poder dictarle al navegador (VTT: Voice To Text), darle comandos de voz y la operación inversa: síntesis de voz desde el propio texto (TTS: Text To Speech), pero eso lo haremos ya en el siguiente artículo.

[alert type=»warning» close=»false»]Ya puedes ver la continuación de este artículo: Reconocimiento y síntesis de voz en el navegador[/alert]

2 COMENTARIOS

  1. A raíz de este artículo me han hecho una pregunta sobre la reproducción automática de audio en Android.

    En Android, el vídeo y el audio no comienzan automáticamente con el autoplay. Me figuro que esto es así intencionadamente para no consumir tarifa de datos del usuario. Para que el método play() funcione, tiene que desencadenarlo una interacción del usuario.

    Algunos utilizan el evento «touchstart», para que la primera vez que el usuario toca la pantalla se desencadene la acción. Y otros lo hacen en el propio controlador del evento del objeto audio/video «canplay».

    En ambos casos funciona en la mayoría de las versiones/navegadores android.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad