Animating Sound in Chrome & Firefox
Tags: autoplay, chrome, firefox, html
Published: 2019-07-12 22:54:18

---
title: Animating Sound in Chrome & Firefox
published: true
description: Getting 'autoplay' to work in Chrome and Firefox when you want to animate your designs with sounds.
tags: autoplay, chrome, firefox, html
---

# Context

I was striving to develop an interactive site for a puppet theater company here in Greece that would bring a taste of the puppet theater experience to the end-user by them simply visiting the site. This resulted in developing a home page that featured several puppet-like characters that would perform a unique move and play a unique sound when the user mouse-over'd them. A demo of the site can be played around with [here](https://oups.netlify.com). And you can view the full source code [here](https://github.com/tmns/oups-puppetry-website).

Getting the characters to perform different moves, which basically amounted to unique CSS transitions, was the easy part. I began to face challenges when attempting to also give the characters a voice. I had set up the appropriate event listeners via JavaScript. But for some reason, when trying the site in Firefox I would hear nothing. Further, in Chrome, I would only hear the appropriate sounds when I had the DevTools open. What could be going wrong??

# Firefox

It turns out that Firefox had begun [blocking autoplay](https://blog.mozilla.org/blog/2019/03/19/todays-firefox-aims-to-reduce-your-online-annoyances/#block-autoplay) some months previously. This seems mainly due to the proliferation of annoying videos that autoplay annoying video things when you're trying to simply read a news article or something of the like. Further, unlike Chrome, Firefox would not conveniently present a dialog box prompting to allow the site to play audio.

So, the natural question to follow then was simply - how do we get the user to give consent to play audio? For my use case, which was not an annoying video but rather a part of the essential animations of the home page puppets, was to create an audio on / off toggle. I accomplished this via the following HTML:

```html
<div class="row d-none d-md-flex flex-column justify-content-center align-items-center fadeInSlow">
  <span class="h3 text-secondary js--soundOn d-none"><i class="fas fa-volume-up"></i></span>
  <span class="h3 text-secondary js--soundOff d-none d-md-block"><i class="fas fa-volume-mute"></i></span>
  <input class="tgl tgl-light js--soundToggle" id="cb1" type="checkbox"/>
  <label class="tgl-btn" for="cb1"></label>
</div>
```

If you look closely at the above snippet, you'll notice that depending on whether the toggle has been switched on or off, the relative classes, `js--soundOn`, `js--soundOff`, and `js--soundToggle` are added to the element's list of classes. Let't also look at the relevant JavaScript:

```javascript
    $('.js--soundToggle').click(function () {
      if ($('.js--soundOff').hasClass('d-md-block')) {
        $('.js--soundOn').addClass('d-md-block');
        $('.js--soundOff').removeClass('d-md-block');
        for (let character of characters) {
          setAudioOnHover(character);
        } 
      } else {
        $('.js--soundOn').removeClass('d-md-block');
        $('.js--soundOff').addClass('d-md-block');
          for (let character of characters) {
            $(`#${character}`).off('mouseenter', playAudio);
            $(`#${character}`).off('mouseleave', pauseAudio);
          }
      }          
    })

[...]

  function setAudioOnHover(character) {
    $(`#${character}`).mouseenter(playAudio);
    $(`#${character}`).mouseleave(pauseAudio);    
  }

  function playAudio () {
    $(`#${this.id}Sound`)[0].currentTime = 0;
    $(`#${this.id}Sound`)[0].play()
      .catch(function (error) {
        // do nothing
      });
  }

  function pauseAudio () {
    $(`#${this.id}Sound`)[0].pause();
  }
``` 

With that, audio in Firefox would play as long as the user had switched the toggle on. But what about Chrome?

# Chrome

In chrome, a dialog box would be presented prompting the user to allow sound to be played for the current site. Also, as long as DevTools was open, audio would play normally. However, if your site must be visited with DevTools open, it definitely is not ready for public use; so, I set out to figure out the appropriate work-around.

The trick here ended up being to simply (but cleverly) utilize an `iframe` to play a silent audio track to trigger the autoplay on first load. Once this was done, the subsequent audio tracks could be played normally. This was particularly great because it could be achieved solely with HTML:

```html
<iframe src="resources/audio/silence.mp3" allow="autoplay" id="audio" style="display:none"></iframe>
```

And that was it! Once the silent audio had triggered the autoplay block, the rest of the character audio animations played without problem.

# Conclusion

Both Firefox and Chrome have recently beefed up their *annoyance prevention* measures, which include preventing media from autoplaying. While I admit this is a useful and welcome feature when dealing with invasive videos or ads with audio, it can also be a barrier when simply trying to bring a website to life with small sets of animations.

Of course though, there is always a loophole. With Firefox, this involves setting up some HTML and JavaScript that takes advantage of the adding and removing of class names to add the audio animations to the characters. In Chrome, it was even easier, as it simply took one line of HTML, a clever `iframe`, to achieve the desired effects.

I hope this helps others stuck in a similar situation. Also, if there are better solutions out there for such a problem, I'm all *ears*! (Okay, I'll stop now >_<)