Skip to content

Hardcoded crossOrigin='anonymous' breaks playback of media served without CORS headers #18

Description

@adamsilverstein

createAudio() unconditionally sets crossOrigin = 'anonymous' on the audio element it creates:

createAudio() {
    if (this.options.audioMode === 'external') {
        this.audio = null;
        return;
    }
    this.audio = new Audio();
    this.audio.preload = this.options.preload || 'metadata';
    this.audio.crossOrigin = 'anonymous';
}

Setting crossOrigin forces the browser to make a CORS request for the media. If the audio file is hosted somewhere that doesn't send Access-Control-Allow-Origin (a common setup: media offloaded to S3/a CDN with default configuration), the request is blocked and playback fails entirely, even though a plain <audio> element would play the same URL fine.

As far as I can tell the attribute isn't needed for the player's core functionality:

  • The audio element is never connected to an AudioContext via createMediaElementSource, so playback doesn't require CORS-clean media.
  • Waveform peak analysis goes through a separate fetch() + decodeAudioData path, which already falls back to placeholder peaks when the fetch fails.

Request: make this configurable, e.g. an options.crossOrigin accepting 'anonymous', 'use-credentials', or null/unset (don't set the attribute). Reading it from a data-cross-origin container attribute like the other options would be ideal. If backwards compatibility allows, defaulting to unset would match what <audio> does natively and avoid the broken-playback failure mode out of the box.

Context: WordPress's Gutenberg Playlist block uses waveform-player and hit this with CDN-hosted media (report: https://core.trac.wordpress.org/ticket/65673). We're currently working around it by clearing audio.crossOrigin right after constructing the player (WordPress/gutenberg#80533), which works because load() is deferred to a requestAnimationFrame callback, but a supported option would let us drop the workaround.

Happy to send a PR if you're open to it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions