skip to Main Content

I’m using the following HTML, CSS and Javascript to disguise a video player as an audio player.

It works perfectly in Firefox but in Chrome pressing the play button does not actually play anything.

What is preventing it from working in chrome and how can I get it to work in Chrome too?

Update:

I want to expand on a observation that I think maybe helpful (A special thank you to @AHaworth for making a similar observation in the comments):

If I remove iframe { display: none; } & the video player initially loads alongside the audio player, the audio player controls (still) has NO effect on the video player. However, if I click play on the video player and then hide it completely using CSS I am now able to fully control the video player through the audio player.. even though the video player is completely hidden.
This observation is similar to @AHaworth in the comments "The error in the console that seems most relevant is the one saying that can’t play the video because the user has not interacted."
So the right approach is to force "interactivity" but how?

Check out the CodePen here.

let player;
const playBtn = document.getElementById('play');
const rewindBtn = document.getElementById('rewind');
const forwardBtn = document.getElementById('forward');
const progressBar = document.getElementById('progress-bar');
const currentTimeEl = document.getElementById('current-time');
const endTimeEl = document.getElementById('end-time');
const speedControl = document.getElementById('speed-control');
const volumeBtn = document.getElementById('volume-btn');
const volumeSlider = document.getElementById('volume-slider');
let duration = 0;

window.addEventListener('load', function() {
  player = new playerjs.Player(document.getElementById("bunny-stream-embed"));
  player.on('ready', () => {
    console.log('Player is ready');
    player.getDuration(d => {
      duration = d;
      endTimeEl.innerText = formatTime(duration);
      progressBar.max = duration;
    });

    // Set initial volume to 70%
    player.setVolume(70);
    volumeSlider.value = 70;
    updateVolumeIcon(0.7);

    // Set up event listeners after player is ready
    setupEventListeners();
  });
  player.on('timeupdate', (data) => {
    currentTimeEl.innerText = formatTime(data.seconds);
    progressBar.value = data.seconds;
  });
  player.on('play', () => {
    playBtn.innerHTML = '❚❚'; // Pause icon
  });
  player.on('pause', () => {
    playBtn.innerHTML = '►'; // Play icon
  });
});

function setupEventListeners() {
  playBtn.addEventListener('click', () => {
    player.getPaused(paused => {
      if (paused) {
        player.play();
      } else {
        player.pause();
      }
    });
  });
  rewindBtn.addEventListener('click', () => {
    player.getCurrentTime(currentTime => {
      player.setCurrentTime(Math.max(0, currentTime - 15));
    });
  });
  forwardBtn.addEventListener('click', () => {
    player.getCurrentTime(currentTime => {
      player.setCurrentTime(Math.min(duration, currentTime + 15));
    });
  });
  progressBar.addEventListener('input', (e) => {
    const time = parseFloat(e.target.value);
    player.setCurrentTime(time);
  });
  volumeSlider.addEventListener('input', (e) => {
    const volume = e.target.value;
    player.setVolume(volume);
    updateVolumeIcon(volume);
  });
  speedControl.addEventListener('click', () => {
    const speedOptions = [1, 1.25, 1.5, 2];
    let currentSpeed = parseFloat(speedControl.innerText.replace('x', ''));
    const newSpeed = speedOptions[(speedOptions.indexOf(currentSpeed) + 1) % speedOptions.length];
    speedControl.innerText = `${newSpeed}x`;
    player.setPlaybackRate(newSpeed);
  });
  volumeBtn.addEventListener('click', () => {
    player.getVolume(volume => {
      if (volume > 0) {
        player.setVolume(0);
        volumeSlider.value = 0;
      } else {
        player.setVolume(70);
        volumeSlider.value = 70;
      }
      updateVolumeIcon(volume > 0 ? 0 : 0.7);
    });
  });
}

function updateVolumeIcon(volume) {
  if (volume > 0.5) {
    volumeBtn.innerHTML = '🔊';
  } else if (volume > 0) {
    volumeBtn.innerHTML = '🔉';
  } else {
    volumeBtn.innerHTML = '🔇';
  }
}

function formatTime(seconds) {
  const mins = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}
body {
  font-family: Arial, sans-serif;
  background-color: #f0f0f0;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

iframe {
  display: none;
}

.audio-player {
  background-color: #1e3d59;
  color: white;
  width: 100%;
  max-width: 800px;
  border-radius: 10px;
  overflow: hidden;
}

.player-top {
  display: flex;
  align-items: center;
  padding: 20px;
}

.cover {
  width: 60px;
  height: 60px;
  border-radius: 5px;
  margin-right: 15px;
}

.info {
  flex-grow: 1;
}

.title {
  margin: 0;
  font-size: 18px;
}

.author {
  margin: 5px 0 0;
  font-size: 14px;
  opacity: 0.8;
}

.bookmark {
  background: none;
  border: none;
  color: white;
  font-size: 24px;
  cursor: pointer;
}

.player-bottom {
  background-color: #102c43;
  padding: 15px 20px;
}

.progress {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
}

#progress-bar {
  flex-grow: 1;
  margin: 0 10px;
  cursor: pointer;
}

.controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.control-btn {
  background: none;
  border: none;
  color: white;
  font-size: 16px;
  cursor: pointer;
}

.play-pause {
  font-size: 24px;
}

.playback-rate,
.volume-control {
  display: flex;
  align-items: center;
}

#volume-slider {
  width: 80px;
  margin-left: 10px;
}

input[type="range"] {
  -webkit-appearance: none;
  background: transparent;
}

input[type="range"]::-webkit-slider-runnable-track {
  width: 100%;
  height: 4px;
  background: #ffffff50;
  border-radius: 2px;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px;
  height: 12px;
  background: white;
  border-radius: 50%;
  cursor: pointer;
  margin-top: -4px;
}
    <script type="text/javascript" src="https:////assets.mediadelivery.net/playerjs/player-0.1.0.min.js"></script>
    <iframe id="bunny-stream-embed" src="https://iframe.mediadelivery.net/embed/197133/dc48a09e-d9bb-420a-83d7-72dc2304c034?autoplay=false&preload=true" width="720" height="400" frameborder="0" allow="autoplay"></iframe>
    
    <div class="audio-player">
        <div class="player-top">
            <img class="cover" src="https://images.blinkist.io/images/books/5bf9dc9c6cee070007cab481/1_1/470.jpg" alt="Book Cover">
            <div class="info">
                <h2 class="title">Atomic Habits</h2>
                <p class="author">James Clear</p>
            </div>
            <button class="bookmark">★</button>
        </div>
        <div class="player-bottom">
            <div class="progress">
                <span id="current-time">00:00</span>
                <input id="progress-bar" type="range" min="0" max="100" value="0">
                <span id="end-time">00:00</span>
            </div>
            <div class="controls">
                <button id="rewind" class="control-btn">← 15</button>
                <button id="play" class="control-btn play-pause">►</button>
                <button id="forward" class="control-btn">15 →</button>
                <div class="playback-rate">
                    <button id="speed-control" class="control-btn">1x</button>
                </div>
                <div class="volume-control">
                    <button id="volume-btn" class="control-btn">🔊</button>
                    <input type="range" id="volume-slider" min="0" max="100" value="70">
                </div>
            </div>
        </div>
    </div>
    
    <script src="script.js"></script>

2

Answers


  1. This is not a full answer,but I put the info here in case it can lead someone to a complete explanation and solution.

    In the given codepen if I change the iframe CSS in the initial stylesheet to:

    iframe {
      opacity: 0;
      z-index: 1;
      position: absolute;
    }
    

    and then where the play arrow gets changed to the pause icon I change the display property of the iframe to ‘none’ the player works.

    player.on('play', () => {
        playBtn.innerHTML = '&#10074;&#10074;'; // Pause icon
       document.getElementById('bunny-stream-embed').style.display = 'none';
    });
    

    or at least, gives the appearance of working, because of course the first click was direct on the iframe rather than one specific spot on the control panel.

    Login or Signup to reply.
  2. 2 ERRORS IN YOU CODE

    1. I noticed that in this piece of code:

           <iframe id="bunny-stream-embed" src="https://iframe.mediadelivery.net/embed/197133/dc48a09e-d9bb-420a-83d7-
         72dc2304c034?autoplay=false&preload=true" width="720" height="400" frameborder="0" allow="autoplay"></iframe>
      

      I know that autoplay doesn’t work. But for newbies or beginners, this is quite confusing: because you are disallowing autoplay and then re-allowing it. So, you have to remove allow="autoplay".

    2. I saw this error when I tested the speedControl button:

      Uncaught TypeError: player.setPlaybackRate is not a function at 
      https://cdpn.io/cpe/boomboom/pen.js?key=pen.js-1bff938b-eb47-861c-0d95- 
      a4f5ea83bed6:77
      

      According to this MDN article, this error appears because the playerjs library may not support the setPlaybackRate function or it may not exist. Try to check the library documentation or try to use the below alternative method:

         speedControl.addEventListener('click', () => {
               const speedOptions = [1, 1.25, 1.5, 2];
               let currentSpeed = parseFloat(speedControl.innerText.replace('x', ''));
               const newSpeed = speedOptions[(speedOptions.indexOf(currentSpeed) + 1) %   
      speedOptions.length];
               speedControl.innerText = `${newSpeed}x`;
               // Alternative method to set playback rate
               player.setPlaybackRate(newSpeed); // Ensure this method is supported
             });
      

    SOLUTION

    Your issue is that Chrome requires user interaction to play media. You can add a user interaction event before hiding the video player:

    playBtn.addEventListener('click', () => {
      player.getPaused(paused => {
        if (paused) {
          player.play();
          document.getElementById('bunny-stream-embed').style.display = 'none';
        } else {
          player.pause();
        }
      });
    });
    

    For more help, you can consult the following sources:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search