Radio La Voz · Ya al Aire
Ushuaia, Tierra del Fuego   54°48'S 68°18'O
Ministerio Casa de Restauración Ushuaia
Casa de Restauración
Ministerio · Ushuaia
Radio La Voz Ushuaia 94.5 MHz
Radio La Voz
FM 94.5 MHz · Ushuaia
Radio La Voz 94.5 MHz
RADIO EN VIVO
Sitio web próximamente

Muy pronto podrás
acceder al contenido

Desde el fin del mundo

La Radio La Voz 94.5 ya transmite desde Ushuaia.
El sitio web completo con predicaciones, programación y contenido del Ministerio Casa de Restauración estará disponible muy pronto.

var playBtn = document.getElementById('player-play-btn'); var playIcon = document.getElementById('play-icon'); var pauseIcon = document.getElementById('pause-icon'); var loader = document.getElementById('player-loader'); var logoWrap = document.querySelector('.player-logo-wrap'); var muteBtn = document.getElementById('player-mute-btn'); var volHighIcon = document.getElementById('volume-high'); var volMuteIcon = document.getElementById('volume-mute'); var volumeSlider = document.getElementById('player-volume-slider'); var volumeFill = document.querySelector('.volume-fill'); var statusBadge = document.getElementById('status-badge'); var statusText = document.getElementById('status-text'); var isPlaying = false; var isBuffering = true; // comienza en CONECTANDO desde el primer frame var lastVolume = 0.8; // Configurar volumen inicial audio.volume = lastVolume; // Lógica de reproducción function togglePlay() { if (isPlaying) { audio.pause(); audio.src = ''; audio.load(); isPlaying = false; isBuffering = false; updateUI(); } else { isBuffering = true; updateUI(); audio.src = streamUrl; audio.load(); var playPromise = audio.play(); if (playPromise !== undefined) { playPromise.then(function() { isPlaying = true; isBuffering = false; updateUI(); }).catch(function(error) { console.error("Error al iniciar reproducción:", error); isPlaying = false; isBuffering = false; updateUI(); }); } } } function updateUI() { statusBadge.className = 'status-badge'; if (isBuffering) { loader.classList.remove('hidden'); playIcon.classList.add('hidden'); pauseIcon.classList.add('hidden'); statusBadge.classList.add('connecting'); statusText.textContent = 'CONECTANDO...'; logoWrap.classList.remove('playing'); } else if (isPlaying) { loader.classList.add('hidden'); playIcon.classList.add('hidden'); pauseIcon.classList.remove('hidden'); statusBadge.classList.add('live'); statusText.textContent = 'RADIO EN VIVO'; logoWrap.classList.add('playing'); } else { loader.classList.add('hidden'); playIcon.classList.remove('hidden'); pauseIcon.classList.add('hidden'); statusBadge.classList.add('paused'); statusText.textContent = 'PAUSADO'; logoWrap.classList.remove('playing'); } } playBtn.addEventListener('click', togglePlay); // Eventos del Elemento Audio audio.addEventListener('waiting', function() { isBuffering = true; updateUI(); }); audio.addEventListener('playing', function() { isPlaying = true; isBuffering = false; updateUI(); }); audio.addEventListener('stalled', function() { // Intentar reconectar si la señal se detiene de forma inesperada if (isPlaying && !audio.paused) { isBuffering = true; updateUI(); } }); audio.addEventListener('error', function(e) { console.error("Error de streaming:", e); isPlaying = false; isBuffering = false; statusBadge.className = 'status-badge'; statusBadge.style.background = 'rgba(239, 68, 68, 0.15)'; statusBadge.style.borderColor = 'rgba(239, 68, 68, 0.4)'; statusBadge.style.color = '#ef4444'; statusText.textContent = 'ERROR DE CONEXIÓN'; loader.classList.add('hidden'); playIcon.classList.remove('hidden'); pauseIcon.classList.add('hidden'); logoWrap.classList.remove('playing'); }); // Controles de Volumen function updateVolume(val) { audio.volume = val; volumeFill.style.width = (val * 100) + '%'; volumeSlider.value = val; if (val === 0) { volHighIcon.classList.add('hidden'); volMuteIcon.classList.remove('hidden'); } else { volHighIcon.classList.remove('hidden'); volMuteIcon.classList.add('hidden'); } } volumeSlider.addEventListener('input', function(e) { var val = parseFloat(e.target.value); updateVolume(val); if (val > 0) { lastVolume = val; } }); muteBtn.addEventListener('click', function() { if (audio.volume > 0) { lastVolume = audio.volume; updateVolume(0); } else { updateVolume(lastVolume); } }); // Lógica del Canvas del Visualizador var canvas = document.getElementById('visualizer-canvas'); var ctx = canvas.getContext('2d'); var barCount = 18; var currentHeights = []; for (var i = 0; i < barCount; i++) { currentHeights.push(0); } function resizeCanvas() { var rect = canvas.parentNode.getBoundingClientRect(); canvas.width = rect.width * window.devicePixelRatio; canvas.height = rect.height * window.devicePixelRatio; ctx.scale(window.devicePixelRatio, window.devicePixelRatio); } window.addEventListener('resize', resizeCanvas); resizeCanvas(); // Dibujo de barras con esquinas redondeadas function drawBar(ctx, x, y, w, h, r) { if (h < 2 * r) r = h / 2; ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); } function drawSpectrum() { var w = canvas.width / window.devicePixelRatio; var h = canvas.height / window.devicePixelRatio; ctx.clearRect(0, 0, w, h); var gap = 4; var barWidth = (w - (gap * (barCount - 1))) / barCount; var time = Date.now() * 0.0035; var ampVolume = audio.volume; if (audio.muted) ampVolume = 0; for (var i = 0; i < barCount; i++) { var targetHeight = 2; // estado base o inactivo if (isPlaying && !isBuffering) { // Algoritmo matemático para simular un ecualizador en vivo muy orgánico var val = Math.sin(i * 0.35 + time * 1.8) * 0.32 + Math.cos(i * 0.65 - time * 2.5) * 0.28 + Math.sin(i * 1.12 + time * 4.2) * 0.18 + Math.sin(time * 0.5 + i * 0.8) * 0.12 + 0.1; // Variaciones aleatorias finas val += (Math.random() - 0.5) * 0.14; // Resaltar frecuencias medias var centerFactor = 1 - Math.abs(i - (barCount / 2)) / (barCount / 2); val += centerFactor * 0.15; // Limitar valores val = Math.max(0.06, Math.min(0.95, val)); var scale = 0.25 + 0.75 * ampVolume; targetHeight = val * h * scale; } else if (isBuffering) { // Animación suave de onda de carga al conectar targetHeight = 4 + Math.sin(time * 4 + i * 0.5) * 2.5; } else { // Movimiento de standby muy sutil al estar pausado targetHeight = 2 + Math.sin(time * 1.5 + i * 0.3) * 0.5; } // Easing de interpolación para transiciones fluidas a 60 FPS currentHeights[i] += (targetHeight - currentHeights[i]) * 0.2; var barH = currentHeights[i]; var barX = i * (barWidth + gap); var barY = h - barH; var grad = ctx.createLinearGradient(0, h, 0, 0); grad.addColorStop(0, '#1d4ed8'); // Azul Ushuaia grad.addColorStop(0.55, '#93c5fd'); // Celeste grad.addColorStop(1, '#c9a84c'); // Oro Ministerio ctx.fillStyle = grad; drawBar(ctx, barX, barY, barWidth, barH, 2.5); } requestAnimationFrame(drawSpectrum); } // ── INICIAR VISUALIZADOR Y UI ── drawSpectrum(); updateVolume(lastVolume); updateUI(); // mostrará CONECTANDO (isBuffering=true desde declaración) // ── LÓGICA DE AUTOPLAY DEFINITIVA ── // // Flujo: // 1. Intentamos reproducir con audio muteado (permitido por browsers). // 2. Si funciona → el evento 'playing' desmutea al volumen del usuario. // 3. Si el browser lo bloquea → NO reseteamos a PAUSADO. // En cambio, quedamos en CONECTANDO y esperamos el PRIMER clic/toque // en CUALQUIER parte de la página para iniciar el stream. // 4. Una vez que el stream arranca (por cualquiera de las dos vías), // desregistramos todos los listeners secundarios. var streamArmed = false; // el stream fue iniciado (intentado) var streamPlaying = false; // el stream realmente suena // El evento 'playing' es la única fuente de verdad para estado EN VIVO audio.addEventListener('playing', function () { if (streamPlaying) return; streamPlaying = true; audio.muted = false; audio.volume = lastVolume; isPlaying = true; isBuffering = false; updateUI(); updateVolume(lastVolume); }); function launchStream() { if (streamArmed) return; streamArmed = true; audio.muted = true; audio.autoplay = true; audio.src = streamUrl; audio.load(); // No usamos el .catch() para resetear estado — // si falla, el listener de clic/toque lo manejará. audio.play().catch(function () { /* bloqueado, esperando gesto */ }); } // Función que se ejecuta ante el PRIMER gesto del usuario en la página function onFirstGesture() { document.removeEventListener('click', onFirstGesture, true); document.removeEventListener('touchstart', onFirstGesture, true); if (!streamPlaying) { // El stream no arrancó aún: lo iniciamos ahora que hay gesto audio.muted = true; audio.src = streamUrl; audio.load(); audio.play().catch(function () { // Si incluso con gesto falla, dejamos el Play manual disponible isBuffering = false; isPlaying = false; updateUI(); }); } } // Armar listener de primer gesto (capture=true para atrapar cualquier clic) document.addEventListener('click', onFirstGesture, true); document.addEventListener('touchstart', onFirstGesture, true); // Intentar autoplay muted inmediatamente launchStream(); })();