el video se descargue automáticamente al detener la grabación

 quieres que el video se descargue automáticamente al detener la grabación y eliminar el botón de descargar. Aquí está la versión modificada:

html
Copy
Download
Run
<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Webcam con Supresor de Ruido y Grabación</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            background-color: #f5f5f5;
        }

        #videoElement {
            width: 100%;
            max-width: 640px;
            background-color: #333;
            margin: 20px 0;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }

        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        button {
            padding: 10px 20px;
            background-color: #4285F4;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
        }

        button:hover {
            background-color: #3367D6;
        }

        button:disabled {
            background-color: #9E9E9E;
            cursor: not-allowed;
        }

        #errorMsg {
            color: #D32F2F;
            margin-top: 20px;
            text-align: center;
        }

        .audio-panel {
            width: 100%;
            max-width: 640px;
            background-color: white;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }

        .meter {
            height: 20px;
            background: #E0E0E0;
            border-radius: 10px;
            overflow: hidden;
            margin-top: 10px;
        }

        .level {
            height: 100%;
            width: 0%;
            background: linear-gradient(to right, #4CAF50, #FFEB3B, #F44336);
            transition: width 0.05s;
        }

        .controls-row {
            display: flex;
            justify-content: space-between;
            margin-top: 10px;
        }

        label {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
        }

        h2 {
            color: #4285F4;
            margin-top: 0;
        }

        #recordingIndicator {
            display: none;
            width: 12px;
            height: 12px;
            background-color: red;
            border-radius: 50%;
            margin-left: 5px;
            animation: pulse 1.5s infinite;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.3; }
            100% { opacity: 1; }
        }

        #timer {
            margin-left: 10px;
            font-weight: bold;
        }
    </style>
</head>

<body>
    <h1>Webcam con Supresor de Ruido</h1>
    <div class="row g-3 align-items-stretch">
        <div class="col-md-6 d-flex">
            <video id="videoElement" autoplay playsinline class="img-fluid rounded w-100 h-auto bg-dark"></video>
        </div>
        <div class="col-md-6 d-flex">
            <div class="card audio-panel w-100">
                <div class="card-body d-flex flex-column">
                    <h2 class="card-title">Control de Audio</h2>
                    <div class="mb-2">Nivel de micrófono:</div>
                    <div class="progress mb-3" style="height: 20px;">
                        <div class="progress-bar" id="audioLevel" role="progressbar" style="width: 0%;"></div>
                    </div>

                    <div class="mt-auto">
                        <div class="form-group mb-3">
                            <div class="form-check form-switch">
                                <input class="form-check-input" type="checkbox" id="noiseSuppression" checked>
                                <label class="form-check-label" for="noiseSuppression">Supresión de ruido</label>
                            </div>
                        </div>

                        <div class="form-group mb-3">
                            <label for="gainControl" class="form-label">Volumen: <span id="gainValue">125%</span></label>
                            <input type="range" class="form-range" id="gainControl" min="0" max="200" value="125">
                        </div>

                        <div class="d-flex justify-content-between gap-2">
                            <div>
                                <button id="startButton" class="btn btn-primary">Iniciar</button>
                                <button id="stopButton" class="btn btn-danger" disabled>Detener</button>
                            </div>
                            <div>
                                <button id="recordButton" class="btn btn-success" disabled>
                                    Grabar
                                    <span id="recordingIndicator"></span>
                                    <span id="timer"></span>
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div id="errorMsg" class="mt-3 alert alert-danger d-none"></div>

    <script>
        // Elementos del DOM
        const videoElement = document.getElementById('videoElement');
        const startButton = document.getElementById('startButton');
        const stopButton = document.getElementById('stopButton');
        const recordButton = document.getElementById('recordButton');
        const recordingIndicator = document.getElementById('recordingIndicator');
        const timerElement = document.getElementById('timer');
        const errorMsg = document.getElementById('errorMsg');
        const audioLevel = document.getElementById('audioLevel');
        const noiseSuppression = document.getElementById('noiseSuppression');
        const gainControl = document.getElementById('gainControl');
        const gainValue = document.getElementById('gainValue');

        // Objetos para el procesamiento de audio y grabación
        let stream = null;
        let audioContext = null;
        let analyser = null;
        let microphone = null;
        let noiseSuppressor = null;
        let gainNode = null;
        let animationId = null;
        let mediaRecorder = null;
        let recordedChunks = [];
        let recordingStartTime = null;
        let timerInterval = null;

        // Iniciar captura
        async function startCapture() {
            try {
                // Solicitar acceso a dispositivos
                stream = await navigator.mediaDevices.getUserMedia({
                    video: true,
                    audio: {
                        noiseSuppression: true,
                        echoCancellation: true,
                        autoGainControl: true
                    }
                });

                // Configurar video
                videoElement.srcObject = stream;

                // Configurar procesamiento de audio
                setupAudioProcessing(stream);

                // Habilitar botones
                startButton.disabled = true;
                stopButton.disabled = false;
                recordButton.disabled = false;
                errorMsg.textContent = '';
            } catch (err) {
                console.error("Error:", err);
                errorMsg.textContent = `Error: ${err.message}`;
            }
        }

        // Configurar procesamiento de audio
        function setupAudioProcessing(stream) {
            // Crear contexto de audio
            audioContext = new(window.AudioContext || window.webkitAudioContext)();

            // Crear nodos de procesamiento
            analyser = audioContext.createAnalyser();
            analyser.fftSize = 64;

            // Nodo de ganancia (control de volumen)
            gainNode = audioContext.createGain();
            updateGain();

            // Conectar el flujo de audio
            microphone = audioContext.createMediaStreamSource(stream);

            // Configurar supresión de ruido (filtro paso alto)
            if (noiseSuppression.checked) {
                setupNoiseSuppression();
            } else {
                microphone.connect(gainNode);
            }

            gainNode.connect(analyser);
            analyser.connect(audioContext.destination);

            // Iniciar visualización
            updateAudioLevel();
        }

        // Configurar supresión de ruido
        function setupNoiseSuppression() {
            if (noiseSuppressor) {
                noiseSuppressor.disconnect();
            }

            // Crear filtro paso alto para reducir ruido de baja frecuencia
            noiseSuppressor = audioContext.createBiquadFilter();
            noiseSuppressor.type = "highpass";
            noiseSuppressor.frequency.value = 150;

            // Conectar los nodos
            microphone.disconnect();
            microphone.connect(noiseSuppressor);
            noiseSuppressor.connect(gainNode);
        }

        // Actualizar control de ganancia
        function updateGain() {
            if (gainNode) {
                const gain = gainControl.value / 100;
                gainNode.gain.value = gain;
                gainValue.textContent = `${gainControl.value}%`;
            }
        }

        // Actualizar visualización de nivel de audio
        function updateAudioLevel() {
            if (!analyser) return;

            const dataArray = new Uint8Array(analyser.frequencyBinCount);
            analyser.getByteFrequencyData(dataArray);

            let sum = 0;
            let count = 0;
            for (let i = 3; i < dataArray.length; i++) {
                sum += dataArray[i];
                count++;
            }
            const average = count > 0 ? sum / count : 0;

            audioLevel.style.width = `${average}%`;

            if (average < 30) {
                audioLevel.style.backgroundColor = "#4CAF50";
            } else if (average < 70) {
                audioLevel.style.backgroundColor = "#FFEB3B";
            } else {
                audioLevel.style.backgroundColor = "#F44336";
            }

            animationId = requestAnimationFrame(updateAudioLevel);
        }

        // Iniciar grabación
        function startRecording() {
            recordedChunks = [];
            
            // Configurar MediaRecorder
            const options = { mimeType: 'video/webm;codecs=vp9' };
            mediaRecorder = new MediaRecorder(stream, options);

            // Evento para recoger datos de grabación
            mediaRecorder.ondataavailable = function(event) {
                if (event.data.size > 0) {
                    recordedChunks.push(event.data);
                }
            };

            // Evento cuando se detiene la grabación
            mediaRecorder.onstop = function() {
                downloadVideo();
            };

            // Iniciar grabación
            mediaRecorder.start(100); // Recoger datos cada 100ms

            // Actualizar UI
            recordButton.textContent = "Detener grabación";
            recordButton.classList.remove("btn-success");
            recordButton.classList.add("btn-warning");
            recordingIndicator.style.display = "inline-block";
            
            // Iniciar temporizador
            recordingStartTime = new Date();
            updateTimer();
            timerInterval = setInterval(updateTimer, 1000);
        }

        // Detener grabación
        function stopRecording() {
            if (mediaRecorder && mediaRecorder.state !== 'inactive') {
                mediaRecorder.stop();
                
                // Detener temporizador
                clearInterval(timerInterval);
                timerElement.textContent = "";
                
                // Actualizar UI
                recordButton.textContent = "Grabar";
                recordButton.classList.remove("btn-warning");
                recordButton.classList.add("btn-success");
                recordingIndicator.style.display = "none";
            }
        }

        // Descargar video grabado
        function downloadVideo() {
            const blob = new Blob(recordedChunks, { type: 'video/webm' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = `grabacion-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}.webm`;
            document.body.appendChild(a);
            a.click();
            setTimeout(() => {
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }, 100);
        }

        // Actualizar temporizador
        function updateTimer() {
            const elapsed = Math.floor((new Date() - recordingStartTime) / 1000);
            const minutes = Math.floor(elapsed / 60).toString().padStart(2, '0');
            const seconds = (elapsed % 60).toString().padStart(2, '0');
            timerElement.textContent = `${minutes}:${seconds}`;
        }

        // Detener captura
        function stopCapture() {
            // Detener grabación si está activa
            if (mediaRecorder && mediaRecorder.state === 'recording') {
                stopRecording();
            }
            
            if (stream) {
                // Detener pistas
                stream.getTracks().forEach(track => track.stop());
                videoElement.srcObject = null;

                // Detener procesamiento de audio
                if (animationId) {
                    cancelAnimationFrame(animationId);
                    animationId = null;
                }
                if (audioContext) {
                    audioContext.close();
                    audioContext = null;
                }

                // Detener temporizador
                clearInterval(timerInterval);

                // Resetear UI
                audioLevel.style.width = "0%";
                startButton.disabled = false;
                stopButton.disabled = true;
                recordButton.disabled = true;
                recordButton.textContent = "Grabar";
                recordButton.classList.remove("btn-warning");
                recordButton.classList.add("btn-success");
                recordingIndicator.style.display = "none";
                timerElement.textContent = "";
            }
        }

        // Event listeners
        startButton.addEventListener('click', startCapture);
        stopButton.addEventListener('click', stopCapture);
        
        recordButton.addEventListener('click', function() {
            if (recordButton.textContent === "Grabar") {
                startRecording();
            } else {
                stopRecording();
            }
        });
        
        noiseSuppression.addEventListener('change', () => {
            if (noiseSuppression.checked && microphone && gainNode) {
                setupNoiseSuppression();
            } else if (microphone && gainNode) {
                microphone.disconnect();
                microphone.connect(gainNode);
            }
        });
        
        gainControl.addEventListener('input', updateGain);

        // Limpiar al salir
        window.addEventListener('beforeunload', stopCapture);
    </script>
</body>
</html>

Cambios principales:

  1. Eliminé el botón de descargar ya que ahora la descarga es automática al detener la grabación.

  2. Modifiqué la función stopRecording() para que:

    • Llame automáticamente a downloadVideo() cuando se detiene la grabación (a través del evento onstop del MediaRecorder)

    • Mantenga la limpieza de la interfaz (temporizador, indicador de grabación, etc.)

  3. La función downloadVideo() ahora se llama automáticamente cuando se detiene la grabación, generando un archivo con nombre basado en la fecha y hora actual.

  4. La interfaz es más limpia con solo tres botones principales: Iniciar, Detener y Grabar/Detener grabación.

El video se descargará automáticamente en formato WEBM cuando el usuario haga clic en "Detener grabación". El nombre del archivo incluirá la fecha y hora de la grabación para facilitar su identificación.

Comentarios

Entradas más populares de este blog

b-Web Speech API

captura video con audio del sistema (como música o sonidos del navegador) pero sin usar el micrófono

EL audio lo envia el navegador-Transcripción de Voz con Whisper