Grabar webcam y audio: la solución simple que no ves a la primera

Muchos piensan en WebRTC para grabar cámara y audio, pero la API MediaRecorder es a menudo la respuesta más directa y sin complicaciones.

Cuando me preguntan cómo grabar video y audio de la webcam de un usuario para guardarlo en el servidor, la respuesta obvia para muchos es irse por la ruta de WebRTC y una conexión P2P complicada. De hecho, la pregunta original en Stack Overflow iba por ahí: establecer una conexión Peer para grabar en el servidor.

Y sí, parece lógico. WebRTC es para comunicación en tiempo real, ¿verdad? Pero ojo que la función .record() de getUserMedia no existe como tal; es una propuesta, no un estándar implementado. Entonces, ¿cómo lo hacemos sin inventar la rueda?

¿Kurento o MediaRecorder? El arte de no sobreingenierar

Aquí es donde entra la discusión clásica sobre la complejidad. Una de las respuestas sugería Kurento, un servidor WebRTC que te permite hacer maravillas: grabar, mezclar streams, aplicar filtros. Es una herramienta potente si necesitas una infraestructura de medios completa.

Pero yo, honestamente, me frustro con la sobreingeniería. Si tu necesidad es solo grabar y guardar, Kurento es como usar un camión para ir a comprar el pan. Es funcional, sí, pero es un overkill brutal. Esto me recuerda una vez que estábamos diseñando una funcionalidad similar y alguien propuso una solución de servidor de medios completa. Mi punto fue: ¿Necesitamos todo eso para esto? Al final, la sencillez ganó.

La alternativa, y la que prefiero en mi caso para escenarios simples, es la API MediaRecorder, directamente en el navegador. Es una solución mucho más directa. Chrome la soporta desde la v47 y Firefox desde la v25. Esto significa que puedes grabar el stream de audio y video directamente en el cliente y luego enviar los trozos (blobs) al servidor.

Grabar directo desde el cliente con MediaRecorder

La mecánica es simple: obtienes el stream con navigator.mediaDevices.getUserMedia, lo pasas a un objeto MediaRecorder, empiezas a grabar, y cuando terminas, la API te entrega los datos en chunks. Esos chunks los puedes convertir en un único Blob y subirlo a tu servidor. De hecho, esta es la solución aceptada en Stack Overflow, y con justa razón.

Aquí te dejo un pedazo de código adaptado que ilustra la idea básica:

'use strict';

const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
const videoElement = document.getElementById('videoElement');
let mediaRecorder;
let recordedChunks = [];

startButton.onclick = async () => {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  videoElement.srcObject = stream;
  videoElement.play();

  mediaRecorder = new MediaRecorder(stream);
  mediaRecorder.ondataavailable = event => {
    if (event.data.size > 0) {
      recordedChunks.push(event.data);
    }
  };
  mediaRecorder.onstop = () => {
    const blob = new Blob(recordedChunks, { type: 'video/webm' });
    // Aquí enviar el 'blob' al servidor con fetch o XMLHttpRequest
    console.log('Video grabado:', blob);
    recordedChunks = [];
  };
  mediaRecorder.start();
  console.log('Grabando...');
};

stopButton.onclick = () => {
  mediaRecorder.stop();
  console.log('Grabación detenida.');
};

Con este enfoque, la carga de procesamiento de medios se mantiene en el cliente, y tu servidor solo recibe un archivo final para almacenar. Es elegante y cumple la función sin añadir una capa de complejidad innecesaria.

Si tuviera que empezar de cero un proyecto que solo necesita grabar la cámara del usuario, iría directo por MediaRecorder sin pensarlo dos veces. Deja las soluciones de servidor de medios para cuando realmente necesites sus funcionalidades avanzadas. La simplicidad muchas veces es la mejor característica.

Jorge RequenaDeveloper full-stack · Chile