Search code examples
htmlfirefoxaudiomp3media

Why can't I get Firefox to play mp3 audio in one of my apps?


I have 2 web apps that present audio using the <audio> HTML tag. I cannot figure out why one app will play the MP3 file and the other will not. I did get this message from Firefox, buried in some others from a Google doc:

All candidate resources failed to load. Media load paused.

Ok... why?

Note: Yes, there are similar questions asked. I read them already. Most of them are also 5-10 years old.

  • Doesn't work on Firefox:

    <audio controls>
      <source src="/media/my_audio.mp3" />
    </audio>
    

    Not working on Firefox

  • Works fine on Firefox:

    <audio controls="">
      <source src="/media/other_audio.mp3">
    </audio>
    

    ...and also in Chrome:

    Just fine in Chrome

  • Other site is working as expected in Firefox:

    Other site working in Firefox

Things I tried:

  1. CORS? In the non-working version, the audio was originally served from a different domain than the page itself. I tried adding crossorigin to the <audio> tag, adding permissive Access-Control-Allow-<stuff>: * headers via the .htaccess file. I even moved the audio file to the same domain. Nothing.
  2. The file itself? Although it worked in Chrome and Edge, I thought maybe there was some sort of problem with the file. So I re-encoded it with FFmpeg. Nope. I thought maybe, because its duration was about 1 hour, it might be the length that was an issue. So I copied a shorter file (actually one from the "working" example site above). Nope. Actually, the "non-working" file plays just fine in Firefox if I navigate directly to the source URL. So I think it's not the file.
  3. Javascript? In the non-working version I have some buttons to jump forward/backward 10 sec, and I manipulate the audio position in JS. I don't see why that would matter, but maybe?
  4. JS #2: The <audio> tag and the rest of that page are created in JS and then added to the page container (no framework, just me). Again, doesn't make sense why that would be an issue, but maybe?
  5. I added the Content-Type: "audio/mpeg" header to .htaccess where the audio is served, but that also didn't help. Tried adding the MIME type to the source tag in HTML, too.

First 40 bytes of the MP3:

FF FB 90 44  00 00 00 00  00 00 00 00  00 00 00 00 
00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00 
00 00 00 00  58 69 6E 67

Supposedly FF FB are magic numbers for MP3 (without ID3v2 metadata). However, I did try a few other MP3s with the page, and none worked. At least one of the others did start with the 3 bytes ID3.

More complete HTML looks like this:

Everything inside #content is being created in JS using document.createElement('template') and then setting innerHTML. The audio URL is inserted via $interview.audio_path. The iframe shows a Google document for editing. This whole #interview-editor element is then added to #content's children.

<body>
    <div id="nav-bar">
        ...
    </div>

    <div id="content">
        <div id="interview-editor" class="right-sidebar">
            <div id="interview-audio">
                <a data-action="replay_30" class="btn-large">30</a>
                <a data-action="replay_10" class="btn-large">10</a>
                <a data-action="replay_5" class="btn-large">5</a>
                <audio id="audio-control" controls src="${interview.audio_path}"></audio>
                <!-- above is what i did originally, then tried this variation as well
                <audio id="audio-control" controls>
                    <source src="${interview.audio_path}">
                </audio> -->
                <a data-action="forward_5" class="btn-large">5</a>
                <a data-action="forward_10" class="btn-large">10</a>
                <a data-action="forward_30" class="btn-large">30</a>
            </div>

            <div id="interview-transcript">
                <iframe src="${interview.text_path}" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>
            </div>

        </div>
    </div>
</body>

There is some JS hooked up to the 6 a.btn-large elements to jump backward and forward in the audio:

    function onButtonClick(btn) {
        // action can be close or one of the audio skip buttons
        const action = btn.dataset.action;

        if (action.startsWith("replay") || action.startsWith("forward")) {
            let [direction, amount] = action.split("_");
            amount = Number(amount);
            if (direction === "replay") amount *= -1
            console.log(`audio seek: ${amount}`);
            const audioControl = document.getElementById("audio-control");
            audioControl.currentTime += amount;
        } else {
            console.error(`error: unknown action ${action}`);
        }
    }

Solution

  • I was able to make my page work with Firefox by delaying setting <audio>'s src attribute until after the new node (#interview-editor) was actually inserted into the page's DOM.

    I did not have to take this step on Chrome, Edge, or Safari.