Search code examples
javascriptsynchronizationhtml5-videohtml5-audio

How to run a function only when two events from two different elements have fired?


I have two media elements:

<audio id="aud"></audio>
<video id="vid"></video>

I've attached media urls to both of them.

Then I load and play them by doing audio.load() and video.load() followed by audio.play() and video.play() in listener

audio.load();
video.load();
video.addEventListener("canplay", () => {
    video.play();     
});
audio.addEventListener("canplay", () => {
    audio.play();     
});

Both start loading, audio loads first and it takes around 1-2 seconds to video to load.

When they actually start playing depends on when "canplay" event is fired by each media elements. (which is fired after loading is done for at-least a couple of frames)

what I wanna do is, call audio.play() AND video.play() together ONLY when "canplay" event is fired for both of them. How can I achieve this?

note that I DO need to use both audio and video element, and i'm trying to achieve a close but not perfect synchronisation at start.

in brief: what i want to achieve is:

audio.load();
video.load();

// when video can "canplay" and when audio can "canplay" ONLY then

video.play();   
audio.play();

Solution

  • Use a global flags:

    let audCanPlay=false;
    let vidCanPlay=false;
    
    function audPlay() {
      audCanPlay=true;
      console.log("audCanPlay=true");
      if(vidCanPlay) playBoth();
    }
    
    function vidPlay() {
      vidCanPlay=true;
      console.log("vidCanPlay=true");
      if(audCanPlay) playBoth();
    }
    
    function playBoth() {
      console.log("audio.play();");
      console.log("video.play();");
    }
    
    /* commented for demonstration
    audio.addEventListener("canplay", audPlay);
    video.addEventListener("canplay", vidPlay);
    audio.load();
    video.load();
    */
    <audio id="aud"></audio>
    <button id="audBtn" onclick="audPlay()">Mimic Audio canplay</button>
    <video id="vid"></video>
    <button id="vidBtn" onclick="vidPlay()">Mimic Video canplay</button>

    I think it's better to add the event listeners before calling the load methods.
    I think it's better to do it this way, rather than waiting for one to finish/canplay and only then call the second = saves time/faster.