Ahora muchos navegadores tienen la habilidad de acceder a la entrada de audio y video desde el usuario. Sin embargo, según el navegador, puede ser una experiencia en línea y totalmente dinámica, o puede ser delegada a otra app en el dispositivo del usuario.
Comienza de forma simple y progresiva
Lo más sencillo es simplemente pedirle al usuario un archivo grabado previamente. Para ello, crea un elemento simple de entrada de archivo y agrega un filtro accept
que indique que solo podemos aceptar archivos de audio y un atributo capture
que indique que queremos obtenerlo directamente desde el micrófono.
<input type="file" accept="audio/*" capture />
Este método funciona en todas las plataformas. En el escritorio, se le solicitará al usuario que cargue un archivo desde el sistema de archivos (ignorando el atributo capture
). En Safari para iOS, se abrirá la app del micrófono, lo que te permitirá grabar audio y, luego, enviarlo de vuelta a la página web. En Android, le permitirá al usuario elegir qué app usar para grabar el audio antes de enviarlo de vuelta a la página web.
Una vez que el usuario haya terminado la grabación y esté de vuelta en el sitio web, tienes que adquirir los datos del archivo de algún modo. Puedes obtener un acceso rápido si
adjuntas un evento onchange
al elemento de entrada y, luego, lees
la propiedad files
del objeto de evento.
<input type="file" accept="audio/*" capture id="recorder" />
<audio id="player" controls></audio>
<script>
const recorder = document.getElementById('recorder');
const player = document.getElementById('player');
recorder.addEventListener('change', function (e) {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
// Do something with the audio file.
player.src = url;
});
</script>
</audio>
Una vez que tengas acceso al archivo, podrás hacer lo que quieras con él. Por ejemplo, puedes hacer lo siguiente:
- Adjuntarlo directamente a un elemento
<audio>
para que puedas reproducirlo - Descárgalo en el dispositivo del usuario
- Subirlo a un servidor adjuntándolo a un
XMLHttpRequest
- Pásalo a través de la Web Audio API y aplícale filtros
Si bien el uso del método de elemento de entrada para la obtención de acceso a los datos de audio es ubicuo, es la opción menos atractiva. Realmente queremos obtener acceso al micrófono y proporcionar una linda experiencia directamente en la página.
Acceder al micrófono de manera interactiva
Los navegadores modernos pueden tener acceso directo al micrófono, lo cual nos permite compilar experiencias que estén totalmente integradas con la página web, de modo que el usuario nunca tenga que abandonar el navegador.
Adquirir acceso al micrófono
Podemos acceder de modo directo al micrófono usando una API en la especificación WebRTC llamada getUserMedia()
. getUserMedia()
le solicitará al usuario acceso a sus micrófonos y cámaras conectados.
Si tiene éxito, la API mostrará un Stream
que contendrá los datos de la cámara o el micrófono, y luego podremos adjuntarlo a un elemento <audio>
, a una transmisión de WebRTC, a un AudioContext
de Web Audio o guardarlo con la API de MediaRecorder
.
Para obtener datos del micrófono, simplemente configuramos audio: true
en el objeto de restricciones que se pasa a la API de getUserMedia()
.
<audio id="player" controls></audio>
<script>
const player = document.getElementById('player');
const handleSuccess = function (stream) {
if (window.URL) {
player.srcObject = stream;
} else {
player.src = stream;
}
};
navigator.mediaDevices
.getUserMedia({audio: true, video: false})
.then(handleSuccess);
</script>
Si quieres elegir un micrófono en particular, primero puedes enumerar los micrófonos disponibles.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'audioinput');
});
Luego, puedes pasar el deviceId
que deseas usar cuando llames a getUserMedia
.
navigator.mediaDevices.getUserMedia({
audio: {
deviceId: devices[0].deviceId,
},
});
Por sí solo, no es tan útil. Todo lo que podemos hacer es tomar los datos de audio y reproducirlos.
Accede a los datos sin procesar desde el micrófono
Para acceder a los datos sin procesar desde el micrófono, tenemos que tomar la transmisión creada por getUserMedia()
y, luego, usar la API de Web Audio para procesar los datos. La API de Web Audio es una API simple que toma fuentes de entrada y las conecta a nodos que pueden procesar los datos de audio (ajustar Gain, etc.) y, en última instancia, a una bocina para que el usuario pueda escucharla.
Uno de los nodos que puedes conectar es un AudioWorkletNode
. Este nodo te brinda la capacidad de bajo nivel para el procesamiento de audio personalizado. El procesamiento de audio real se realiza en el método de devolución de llamada process()
en AudioWorkletProcessor
.
Llama a esta función para ingresar entradas y parámetros, y recuperar resultados.
Consulta Cómo ingresar una worklet de audio para obtener más información.
<script>
const handleSuccess = async function(stream) {
const context = new AudioContext();
const source = context.createMediaStreamSource(stream);
await context.audioWorklet.addModule("processor.js");
const worklet = new AudioWorkletNode(context, "worklet-processor");
source.connect(worklet);
worklet.connect(context.destination);
};
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(handleSuccess);
</script>
// processor.js
class WorkletProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
// Do something with the data, e.g. convert it to WAV
console.log(inputs);
return true;
}
}
registerProcessor("worklet-processor", WorkletProcessor);
Los datos que se mantienen en los búferes son datos sin procesar del micrófono y tienes un número de opciones de lo que puedes hacer con ellos:
- Sube los archivos directamente al servidor
- Almacenarlos localmente
- Conviértelos en un formato de archivo dedicado, como WAV y, luego, guárdalos en tus servidores o de forma local
Guarda los datos del micrófono
La forma más sencilla de guardar los datos del micrófono es usar la API de MediaRecorder
.
La API de MediaRecorder
tomará la transmisión creada por getUserMedia
y, luego, guardará de forma progresiva los datos que están en la transmisión en tu destino preferido.
<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
const downloadLink = document.getElementById('download');
const stopButton = document.getElementById('stop');
const handleSuccess = function(stream) {
const options = {mimeType: 'audio/webm'};
const recordedChunks = [];
const mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener('dataavailable', function(e) {
if (e.data.size > 0) recordedChunks.push(e.data);
});
mediaRecorder.addEventListener('stop', function() {
downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'acetest.wav';
});
stopButton.addEventListener('click', function() {
mediaRecorder.stop();
});
mediaRecorder.start();
};
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(handleSuccess);
</script>
En nuestro caso, estamos guardando los datos directamente en un array que luego podemos convertir en un Blob
, que se puede usar para guardar los datos en nuestro servidor web o directamente en el almacenamiento del dispositivo del usuario.
Solicitar permiso para usar el micrófono de forma responsable
Si el usuario no le otorgó acceso al micrófono a tu sitio anteriormente, en el momento en que llames a getUserMedia
, el navegador le solicitará al usuario que le otorgue permiso a tu sitio para acceder al micrófono.
A los usuarios no les gusta que se les solicite acceso a los dispositivos potentes de su máquina y, con frecuencia, bloquean la solicitud o la ignoran si no comprenden el contexto por el cual se creó la solicitud. Es mejor solo pedir acceso al micrófono la primera vez que se necesita. Una vez que el usuario otorgue el acceso, no se le volverá a preguntar. Sin embargo, si lo rechaza, no podrás volver a pedirle permiso.
Usa la API de permisos para comprobar si ya tienes acceso
La API de getUserMedia
no te permite saber si ya tienes acceso al micrófono. Esto te presenta un problema, para proporcionar una buena IU para hacer que el usuario te otorgue acceso al micrófono, tienes que pedir acceso al micrófono.
Esto se puede resolver en algunos navegadores usando la Permission API. La API de navigator.permission
te permite consultar el estado de la capacidad de acceder a APIs específicas sin tener que volver a solicitar.
Para consultar si tienes acceso al micrófono del usuario, puedes pasar {name: 'microphone'}
al método de consulta y mostrará lo siguiente:
granted
: El usuario te otorgó acceso al micrófono anteriormente.prompt
: El usuario no te otorgó acceso y se lo solicitarán cuando llames agetUserMedia
.denied
: El sistema o el usuario bloqueó explícitamente el acceso al micrófono y no podrás obtener acceso al mismo.
Ahora puedes comprobar rápidamente si necesitas modificar tu interfaz de usuario para acomodar las acciones que el usuario necesita tomar.
navigator.permissions.query({name: 'microphone'}).then(function (result) {
if (result.state == 'granted') {
} else if (result.state == 'prompt') {
} else if (result.state == 'denied') {
}
result.onchange = function () {};
});