En este post vamos a ver cómo grabar el audio proveniente del micrófono con JavaScript y PHP.
Vamos a acceder al micrófono con JavaScript y enviar el resultado a un servidor con PHP para almacenar la grabación como un archivo de audio; además, haremos que se pueda seleccionar un distinto dispositivo de grabación.
Grabar audio con JavaScript y enviarlo a servidor con PHP
Gran parte de este trabajo está basado en mi post anterior: cómo grabar audio del micrófono con JavaScript y descargar el archivo. Te recomiendo leerlo, porque saltaré la parte de la grabación con MediaRecorder.
Lo único que cambia es que ahora, en lugar de descargar el archivo, vamos a enviarlo a PHP usando fetch
(un remplazo nativo a XMLHttpRequest
) y FormData.
El código completo está en GitHub, analízalo ahí si quieres; aquí me encargaré de explicar las partes más importantes.
El evento stop de MediaRecorder
Normalmente descargamos el audio grabado con el siguiente código:
// Cuando se detenga (haciendo click en el botón) se ejecuta esto
mediaRecorder.addEventListener("stop", () => {
// Detener el stream
stream.getTracks().forEach(track => track.stop());
// Detener la cuenta regresiva
detenerConteo();
// Convertir los fragmentos a un objeto binario
const blobAudio = new Blob(fragmentosDeAudio);
// Crear una URL o enlace para descargar
const urlParaDescargar = URL.createObjectURL(blobAudio);
// Crear un elemento <a> invisible para descargar el audio
let a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = urlParaDescargar;
a.download = "grabacion_parzibyte.me.webm";
// Hacer click en el enlace
a.click();
// Y remover el objeto
window.URL.revokeObjectURL(urlParaDescargar);
});
Pero ahora lo vamos a enviar a un servidor con PHP así que el BLOB lo adjuntamos en un FormData y lo mandamos a PHP, de la siguiente manera:
// Cuando se detenga (haciendo click en el botón) se ejecuta esto
mediaRecorder.addEventListener("stop", () => {
// Detener el stream
stream.getTracks().forEach(track => track.stop());
// Detener la cuenta regresiva
detenerConteo();
// Convertir los fragmentos a un objeto binario
const blobAudio = new Blob(fragmentosDeAudio);
const formData = new FormData();
// Enviar el BinaryLargeObject con FormData
formData.append("audio", blobAudio);
const RUTA_SERVIDOR = "guardar.php";
$duracion.textContent = "Enviando audio...";
fetch(RUTA_SERVIDOR, {
method: "POST",
body: formData,
})
.then(respuestaRaw => respuestaRaw.text()) // Decodificar como texto
.then(respuestaComoTexto => {
// Aquí haz algo con la respuesta ;)
console.log("La respuesta: ", respuestaComoTexto);
// Abrir el archivo, es opcional y solo lo pongo como demostración
$duracion.innerHTML = `<strong>Audio subido correctamente.</strong> <a target="_blank" href="${respuestaComoTexto}">Abrir</a>`
})
});
PHP devuelve el nombre del archivo que se acaba de guardar, así que proporcionamos un enlace para que el usuario pueda verlo. Esto es totalmente opcional, pero lo hago así para demostrarlo.
Por cierto, la ruta del script de php es guardar.php, podría ser otra ruta u otro nombre.
Recibir grabación en PHP
En la parte del servidor recibimos el archivo en el arreglo superglobal $_FILES
y lo movemos a la ubicación del script, como vimos en este post de subida de archivos con PHP.
<?php
/**
* Grabar audio obtenido del micrófono con JavaScript, seleccionando
* un dispositivo de grabación de una lista; usando MediaRecorder
* y getUserMedia
*
* Extra: no descargar el audio, sino enviarlo a un servidor con PHP y guardarlo en la nube
* Recomendado: https://parzibyte.me/blog/2018/11/06/cargar-archivo-php-javascript-formdata/
*
*
* @author parzibyte
* @see https://parzibyte.me/blog
*/
# Si no hay archivos, salir inmediatamente
if (count($_FILES) <= 0 || empty($_FILES["audio"])) {
exit("No hay archivos");
}
# De dónde viene el audio y en dónde lo ponemos
$rutaAudioSubido = $_FILES["audio"]["tmp_name"];
$nuevoNombre = uniqid() . ".webm";
$rutaDeGuardado = __DIR__ . "/" . $nuevoNombre;
// Mover el archivo subido a la ruta de guardado
move_uploaded_file($_FILES["audio"]["tmp_name"], $rutaDeGuardado);
// Imprimir el nombre para que la petición lo lea
echo $nuevoNombre;
Obtenemos un nombre único con uniqid
(aunque no criptográficamente seguro pero no importa, solo queremos aleatoridad) y guardamos el archivo. Al final imprimimos el nombre para regresarlo en la petición de JavaScript.
Conclusión
De esta manera queda demostrado que es totalmente posible grabar el audio del micrófono con JavaScript y enviar la grabación a un servidor con PHP.
Si tienes dudas sobre el formato, la obtención de permisos, compatibilidad con navegadores y otras cosas, mira el post anterior.
Hola, no se me llena el cuadro con los dispositivos de entrada. ¿Que podria ser?
Puede que no existan dispositivos de entrada, no cuente con los permisos o no esté en un sitio seguro, entre otras cosas
la forma de guarlarlo en NODE seria igual?
Hola, he seguido tu tutorial y he logrado guardar el audio. Hasta reproducirlo en la web pero tengo problemas cuando se reproduce con una aplicación privada desarrollada en Android.
Según me indican el audio se reproduce, pero no detecta la duración del archivo y el scroll de reproducción queda en 0.
Sabes como asignar la duración al archivo o que configuración adicional se debe hacer para no tener este problema? Gracias por la info
Hola. No, no lo sé; me parece que es por el formato de audio que no se tiene la duración, lo mismo me pasó al reproducirlo con VLC.
Saludos