Grabar sonido JS desde un micr贸fono o comentarios de voz
No hace mucho tiempo, al desarrollar una aplicaci贸n web corporativa, el cliente deseaba poder dejar comentarios de voz. Anteriormente, no encontr茅 la creaci贸n de contenido de medios y comenc茅 a estudiar este tema con inter茅s.
La red proporcion贸 suficiente informaci贸n de fondo sobre el tema de crear y procesar este tipo de contenido, pero no encontr茅 un ejemplo simple y completamente funcional. Despu茅s de la implementaci贸n de la tarea por parte del cliente, decid铆 publicar el ejemplo m谩s simplificado de grabar y guardar comentarios de voz y escribir un art铆culo. Quiz谩s este material sea 煤til para alguien y ayude en el estudio.
Declaraci贸n del problema.
Nos propusimos la tarea de desarrollar una mini aplicaci贸n que se ejecute en un navegador que le permita grabar un comentario de voz, enviar una grabaci贸n al servidor, el servidor guardar谩 la grabaci贸n, si tiene 茅xito, devolver谩 una respuesta con el nombre del archivo creado y mostrar谩 el objeto en la p谩gina para que se pueda escuchar la grabaci贸n.
Grabar sonido en el navegador
Se decidi贸 implementar la grabaci贸n de sonido utilizando la API web de grabaci贸n de MediaStream. Para la grabaci贸n, utilizamos la interfaz MediaRecorder (). Pero primero, crea una interfaz. Tengamos index.html que contiene solo las etiquetas m谩s b谩sicas, y en el cuerpo de la etiqueta incluiremos un archivo con nuestro futuro JavaScript voice.js:
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>Voice comments</title> </head> <body> <script src="voice.js"></script> </body> </html>
Cree un archivo voice.js, defina una URL constante que contenga un enlace a un script que reciba sonido grabado. A continuaci贸n, cree los botones Iniciar y Parar para iniciar y detener la grabaci贸n de sonido, as铆 como el bloque div en el que se mostrar谩n los registros guardados. En esto nuestra interfaz est谩 lista, puede proceder directamente a la grabaci贸n de sonido.
Como ya se mencion贸 para la grabaci贸n, utilizaremos la interfaz MediaRecorder () (para obtener m谩s informaci贸n sobre la interfaz, consulte la documentaci贸n), para su funcionamiento es necesario determinar la secuencia de medios de la que tomaremos sonido, inicial铆cela solo porque solo necesitamos una pista de audio.
navigator.mediaDevices.getUserMedia({ audio: true}) .then(stream => { const mediaRecorder = new MediaRecorder(stream)});
Ahora tenemos el mediaRecorder constante, que contiene una instancia de la interfaz, y continuaremos trabajando con ella.
Para comenzar a grabar, debemos llamar al m茅todo MediaRecorder.start (), para detener la grabaci贸n, al m茅todo MediaRecorder.stop (). En este caso, MediaRecorder.stop () genera un evento disponible de datos a trav茅s del cual tenemos acceso a la grabaci贸n de sonido digitalizada en forma de una matriz binaria.
Entonces, describiremos los eventos anteriores, declararemos la matriz de voz [] y escribiremos los datos recibidos en ella:
navigator.mediaDevices.getUserMedia({ audio: true}) .then(stream => { const mediaRecorder = new MediaRecorder(stream); let voice = []; document.querySelector('#start').addEventListener('click', function(){ mediaRecorder.start(); }); mediaRecorder.addEventListener("dataavailable",function(event) { voice.push(event.data); }); document.querySelector('#stop').addEventListener('click', function(){ mediaRecorder.stop(); }); });
Ahora prepararemos los datos recibidos para enviar. Para hacer esto, mediante el evento stop, cree una instancia BLOB, coloque los datos recibidos y especifique el tipo de datos MIME. En nuestro caso, ser谩 audio / wav.
mediaRecorder.addEventListener("stop", function() { const voiceBlob = new Blob(voice, { type: 'audio/wav' });
Como resultado, tenemos una constante voiceBlob en la que se encuentra el contenido de nuestro futuro archivo wav con la grabaci贸n de un mensaje de voz.
Enviar un registro al servidor
Para enviar un registro al servidor, decid铆 usar el m茅todo fetch (). Dado que este m茅todo es el m谩s moderno y proporciona una interfaz mejorada para realizar solicitudes al servidor. Como parte de nuestra tarea, debemos iniciar una solicitud POST en el cuerpo para enviar el contenido de nuestro archivo futuro para guardar en el servidor (c贸mo funciona el m茅todo fetch () y qu茅 capacidades se pueden encontrar en la documentaci贸n en detalle). Cree un nuevo formulario con el campo de voz y coloque el contenido de nuestro registro en 茅l.
let fd = new FormData(); fd.append('voice', voiceBlob);
Creamos una funci贸n asincr贸nica para enviar un mensaje al servidor para recibir una respuesta y mostrar un objeto de audio para reproducir un archivo ya guardado. Como argumento, la funci贸n tomar谩 la forma creada anteriormente.
Iniciamos una solicitud del servidor:
let promise = await fetch(URL, { method: 'POST', body: form});
Si la respuesta HTTP del servidor no contiene un c贸digo de error (el c贸digo de respuesta est谩 en el rango de 200-299), entonces nos queda por descifrar la respuesta, crear un nuevo objeto de audio en la p谩gina, determinar sus propiedades y mostrarlo. La forma en que se forma la respuesta se discutir谩 a continuaci贸n.
Guardar un archivo en el servidor
Creemos un script en el servidor que recibir谩 nuestra solicitud POST con un mensaje de voz. Dado que la grabaci贸n de sonido que enviamos es esencialmente un archivo en forma, la recibiremos en el servidor en consecuencia:
$uploadDir = 'voice/'; $typeFile = explode('/', $_FILES['voice']['type']); $uploadFile = $uploadDir . basename(md5($_FILES['voice']['tmp_name'].time()).'.'.$typeFile[1]); if (move_uploaded_file($_FILES['voice']['tmp_name'], $uploadFile)) { $response = ['result'=>'OK', 'data'=>'../'.$uploadFile]; } else { $response = ['result'=>'ERROR', 'data'=>'']; } echo json_encode($response);
Puede encontrar muchos ejemplos similares de c贸digo PHP, procesando archivos recibidos en la red. Primero, inicialice las variables, $ uploadDir: el directorio en el que se guardar谩 el archivo recibido, el tipo de archivo y tipo de archivo en nuestro caso ser谩 igual a wav y el nombre completo del archivo, incluido el directorio. El nombre de archivo en este caso se forma combinando el nombre de archivo "temporal" y el valor de cadena de la hora actual cifrada usando el m茅todo md5. Si guarda con 茅xito el archivo con un mensaje de voz en el directorio especificado, formamos una respuesta en forma de matriz que contiene el campo de resultado igual a "OK" o "ERROR" dependiendo del resultado y el campo de "datos" que, en caso de procesamiento exitoso, contiene un enlace al archivo guardado.
Por conveniencia, transformamos la matriz en un objeto JSON y lo enviamos como respuesta.
El c贸digo de muestra completo est谩 disponible en
GitHub .
PD: el navegador le permite grabar contenido multimedia solo con una conexi贸n HTTPS segura.