Howler.js: Globally check if audio is unlocked?

Created on 21 Mar 2019  路  4Comments  路  Source: goldfire/howler.js

Is there a good way to check if the audio has been unlocked with a click/touch event? I know I can listen for the unlock event, but if it has already been emitted by the time I add the event listener, I'll be stuck waiting forever.

The simplest solution I can think of is to make Howler._audioUnlocked public. It would also be nice to be able to listen to unlock events without creating a Howl instance.

Most helpful comment

@goldfire any news on this?
Is there any workaround that tells us both that audio is locked, and that it has not yet been unlocked?

We can check if it's been unlocked by listening to the onunlock event, but if that event hasn't fired, it either means audio isn't locked, or it is but hasn't been unlocked yet.

All 4 comments

This is currently not possible, which is why it is frustrating that the browser vendors went ahead with the auto play changes before finalizing the new spec changes. I'm watching the progress on that and will get howler updated with the ability to check this once the browsers update with this ability.

I don't understand. Isn't _audioUnlocked used to keep track of this state? In my app I'm polling Howler. _audioUnlocked in a promise and it's working fine (though I've only tested in Chrome). Maybe I didn't describe my use-case well enough:

I'm building a SPA with several pages that include audio and animation that should play immediately. The animations must be in-sync with the audio. If the user navigates to an animation page using an internal link (no refresh), I'll miss the unlock event since the unlock listener won't be bound until after the user has clicked a link. If the user navigates to an animation page using an external link or hard refreshes, I need to wait for the unlock event.

In the first case, I have no way of knowing that the unlock event has already been fired, so I'll end up waiting forever. But if I don't wait for the unlock event, the animation will play incorrectly (audio will fail to start, but the visual animation will play).

What I need: a function that behaves the same regardless of whether or not the unlock event has fired. This is what I'm using, but I would prefer to not rely on a variable that appears to be private:

import { Howler } from 'howler';

const checkInterval = 250; // ms

export default function waitForUnlock() {
  const promise = new Promise(resolve => {
    if (checkUnlocked()) {
      // resolve immediately if already unlocked
      resolve();
    } else {
      // wait for unlock
      setInterval(checkUnlocked, checkInterval);
    }
    function checkUnlocked() {
      if (Howler._audioUnlocked) {
        resolve();
        return true;
      }
      return false;
    }
  });

  return promise;
}

I also figured this could be done internally without setInterval.

That is the best you can do at the moment. That variable would be confusing if it was public because it suggests that if it is false then the audio can't currently be played, which isn't always the case. That is just tracking if the auto unlock system has been run or not. A browser API is in the works to be able to determine if the audio is actually able to be played or not, so once that is in place I'll add a public method/property.

@goldfire any news on this?
Is there any workaround that tells us both that audio is locked, and that it has not yet been unlocked?

We can check if it's been unlocked by listening to the onunlock event, but if that event hasn't fired, it either means audio isn't locked, or it is but hasn't been unlocked yet.

Was this page helpful?
0 / 5 - 0 ratings