openvibers/openvibe.live Commits

Stream player: a muted autoplay shows a 'Tap for sound' pill over the live picture (it was a dark overlay hiding the stream); a tap anywhere or a media volume key brings the sound in (#358)

OP OpenVibers committed 19 days ago · 00f02edc4b · 2 files, +26 −22

Changes

ddiff --git a/public/css/style.css b/public/css/style.css
iindex 33c27dd7..73759f90 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -2107,6 +2107,13 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
/* Viewers and uptime: plain stats on the bar, not coloured pills (owner, 2026-10-20: "this gui should be improved"). */
.viewer-badge i, .uptime-badge i { color: rgba(255,255,255,0.65); }
++/* Muted by the browser's autoplay rule: the stream stays in view, a pill says so, and a tap anywhere on it brings the sound
++ in (stream-player.js showUnmuteOverlay; the same look as the shared player's "Tap for sound"). */
++.unmute-overlay { position: absolute; inset: 0; z-index: 20; cursor: pointer; background: transparent; -webkit-tap-highlight-color: transparent; }
++.unmute-pill { position: absolute; left: 12px; top: 12px; display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px 8px 11px; border-radius: 999px; background: rgba(0,0,0,0.66); color: #fff; font: 650 13px/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); box-shadow: 0 4px 18px rgba(0,0,0,0.35); animation: unmute-pop .3s ease-out both; }
++.unmute-overlay:hover .unmute-pill, .unmute-overlay:focus-visible .unmute-pill { background: var(--accent-strong, var(--accent, #3b82f6)); color: var(--on-accent-strong, #fff); }
++@keyframes unmute-pop { from { opacity: 0; transform: translateY(-4px) scale(.96); } }
++@media (prefers-reduced-motion: reduce) { .unmute-pill { animation: none; } }
/* ── DVR Progress Bar (Live Stream Seeking) ─────────────────── */
.dvr-progress-wrap {
ddiff --git a/public/js/stream-player.js b/public/js/stream-player.js
iindex c4f9e61a..d3a18a6a 100644
---- a/public/js/stream-player.js
++++ b/public/js/stream-player.js
@@@ -1040,14 +1040,10 @@ function startJSMPEG(wsUrl, canvas, placeholder, bufferProfile = getJsmpegBuffer
if (container && !document.getElementById('unmute-overlay')) {
const overlay = document.createElement('div');
overlay.id = 'unmute-overlay';
-- overlay.style.cssText = 'position:absolute;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;cursor:pointer;background:rgba(0,0,0,0.45);transition:background 0.2s;';
-- overlay.innerHTML = `
-- <div style="display:flex;flex-direction:column;align-items:center;gap:12px;">
-- <div style="width:72px;height:72px;border-radius:50%;background:rgba(255,255,255,0.15);border:2px solid rgba(255,255,255,0.6);display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px);transition:transform 0.15s,background 0.15s;">
-- <i class="fa-solid fa-play" style="font-size:1.8rem;color:#fff;margin-left:4px;"></i>
-- </div>
-- <span style="color:#fff;font-size:0.9rem;opacity:0.85;text-shadow:0 1px 4px rgba(0,0,0,0.6);">Click to enable audio</span>
-- </div>`;
++ overlay.className = 'unmute-overlay';
++ overlay.setAttribute('role', 'button');
++ overlay.setAttribute('aria-label', 'Turn the sound on');
++ overlay.innerHTML = '<span class="unmute-pill"><i class="fa-solid fa-volume-xmark"></i> Tap for sound</span>';
overlay.addEventListener('click', () => {
audioCtx.resume().then(() => {
console.log('[JSMPEG] AudioContext resumed by user click');
@@@ -3578,9 +3574,16 @@ function _clearStreamError() {
}
}
++// The media volume keys (UI Events names, and the older ones): while the stream is muted for autoplay, volume up is a tap.
++document.addEventListener('keydown', (e) => {
++ if (!/^(AudioVolumeUp|VolumeUp|AudioVolumeMute|VolumeMute)$/.test(e.key)) return;
++ const overlay = document.getElementById('unmute-overlay');
++ if (overlay) overlay.click();
++});
++
/**
-- * Show a click-to-play overlay when autoplay policy forced muted playback.
-- * One tap unmutes, restores volume, and removes the overlay.
++ * Show a "Tap for sound" pill when autoplay policy forced muted playback.
++ * One tap anywhere on the picture unmutes, restores volume, and removes it.
*/
function showUnmuteOverlay(video) {
// Don't duplicate
@@@ -3589,18 +3592,12 @@ function showUnmuteOverlay(video) {
if (!container) return;
const overlay = document.createElement('div');
overlay.id = 'unmute-overlay';
-- overlay.style.cssText = 'position:absolute;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;cursor:pointer;background:rgba(0,0,0,0.45);transition:background 0.2s;';
-- overlay.innerHTML = `
-- <div style="display:flex;flex-direction:column;align-items:center;gap:12px;">
-- <div style="width:72px;height:72px;border-radius:50%;background:rgba(255,255,255,0.15);border:2px solid rgba(255,255,255,0.6);display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px);transition:transform 0.15s,background 0.15s;">
-- <i class="fa-solid fa-play" style="font-size:1.8rem;color:#fff;margin-left:4px;"></i>
-- </div>
-- <span style="color:#fff;font-size:0.9rem;opacity:0.85;text-shadow:0 1px 4px rgba(0,0,0,0.6);">Click to enable audio</span>
-- </div>`;
-- // Hover effect on the play circle
-- const circle = overlay.querySelector('div > div');
-- overlay.addEventListener('mouseenter', () => { if (circle) { circle.style.transform = 'scale(1.1)'; circle.style.background = 'rgba(255,255,255,0.25)'; } });
-- overlay.addEventListener('mouseleave', () => { if (circle) { circle.style.transform = ''; circle.style.background = ''; } });
++ overlay.className = 'unmute-overlay';
++ overlay.setAttribute('role', 'button');
++ overlay.setAttribute('aria-label', 'Turn the sound on');
++ // The stream stays in view (owner, 2026-10-25): a small pill says it is muted, and a tap anywhere on the picture or a
++ // media volume key (where the browser passes it to the page) turns the sound on.
++ overlay.innerHTML = '<span class="unmute-pill"><i class="fa-solid fa-volume-xmark"></i> Tap for sound</span>';
overlay.addEventListener('click', () => {
video.muted = false;
// Restore volume from saved preference / slider