MediaElementAudioSource outputs zeroes due to CORS access restrictions

<script>
// Create a new instance of an audio object and adjust some of its properties
var audio = new Audio();
audio.src = 'http://subdomain.domain.org:port/;stream/1';
audio.controls = true;
audio.loop = true;
audio.autoplay = true;
audio.crossorigin="anonymous";
// Establish all variables that your Analyser will use
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
// Initialize the MP3 player after the page loads all of its HTML into the window
window.addEventListener("load", initMp3Player, false);
function initMp3Player(){
    document.getElementById('audio_box').appendChild(audio);
    context = new (window.AudioContext || window.webkitAudioContext)(); // AudioContext object instance // AudioContext object instance
    analyser = context.createAnalyser(); // AnalyserNode method
    canvas = document.getElementById('analyser_render');
    ctx = canvas.getContext('2d');
    // Re-route audio playback into the processing graph of the AudioContext
    source = context.createMediaElementSource(audio);
 source.crossOrigin = 'anonymous'   
    source.connect(analyser);
    analyser.connect(context.destination);
    frameLooper();
}
// frameLooper() animates any style of graphics you wish to the audio frequency
// Looping at the default frame rate that the browser provides(approx. 60 FPS)
function frameLooper(){
    (requestAnimationFrame || webkitRequestAnimationFrame)(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);//get frequency

    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
    ctx.fillStyle = '#00CCFF'; // Color of the bars
    bars = 100;
    for (var i = 0; i < bars; i++) {
        bar_x = i * 3;
        bar_width = 2;
        bar_height = -(fbc_array[i] / 2);
        //  fillRect( x, y, width, height ) // Explanation of the parameters below
        ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
}
</script>

Audio API gives MediaElementAudioSource outputs zeroes due to CORS access restrictions because I'm trying to play a SHOUTcast URL. I don't know what to do; I have tried all solutions on the internet but nothing worked. Any help will be appreciated.

The URL works perfectly with audio element so its not about the URL; I have even tried something like http://subdomain.domain.org:port/file.mp3. And I found on the internet people using Icecast which is .ogg have same problem. How to fix this?

Answers:

Answer

In my response I will assume the following setup:

To get this working you need:

  1. Set the "Access-Control-Allow-Origin" header of your stream to your domain or *
  2. In javascript, set audio tag crossOrigin property to "anonymous" audio.crossOrigin="anonymous";
  3. Another option it to move you stream URL to the original domain using reverse proxy.

With Icecast you cat set the "Access-Control-Allow-Origin" header using configuration file, just add the following lines to your icecast.xml, I usually add them right after the opening <icecast> tag:

<http-headers>
        <header name="Access-Control-Allow-Origin" value="*" />
        <header name="Access-Control-Allow-Headers" value="Origin, Accept, X-Requested-With, Content-Type, If-Modified-Since" />
        <header name="Access-Control-Allow-Methods" value="GET, OPTIONS, HEAD" />
</http-headers>

Don't forget to restart Icecast after these changes. When your Icecast will be back online you can check the headers with this command:

lynx -head -dump http://stream.radio.com:8000/mount 

Response should look something like this:

Server: Icecast 2.4.2
....
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type, If
-Modified-Since
Access-Control-Allow-Methods: GET, OPTIONS, HEAD

As you can see, "Access-Control-Allow-Origin: *" header is present.

Shoutcast

Unfortunately, Shoutcast does not allow you to set HTTP headers (.htaccess is not an option too), but we can create a reverse proxy in web server configuration, this will allow you to host the stream from the main domain - radio.com. I will provide proxy configurations for Nginx and Apache.

Nginx

You can add additional headers with "proxy_set_header", but the basic example is:

server {
    listen   80;
    server_name radio.com;
    ....
    location /stream { 
       proxy_set_header X-Forwarded-For $remote_addr; 
       proxy_pass http://stream.radio.com:8000/mount; 
    }
    ....
}

Apache

Activate Apache proxy modules, and update radio.com virtual host configuration configuration:

<VirtualHost *:80>
   ServerName radio.com
   ....
   ProxyPass /stream http://stream.radio.com:8000/mount
</VirtualHost>

Now you can access your stream using http://radio.com/stream URL and the CORS policy will not apply. This solution also brings some additional perks:

  • you can convert your http Shoutcast/Icecast stream to https, so the browsers will not complain about accessing unsecure content when you will embed your stream to the page hosted with https. (Icecast supports SSL configuration itself)
  • 8000 port will be replaced with port 80, that will allow listeners with 8000 port behind firewall to access your stream.
Answer

That is an HTTP header. You would configure your webserver or webapp to send this header. Perhaps in htaccess or PHP. remove the below line

    <header name = "Access-Control-Allow-Origin" value = "*" />
Answer

SHOUTcast servers do not support CORS. There is nothing you can do to change this if you are going to continue to use SHOUTcast.

Answer

First of all, MediaElementAudioSource doesn't have a property named "crossOrigin".

I just find this problem, and mad with the Message:MediaElementAudioSource outputs zeroes due to CORS access restrictions for. But it's just a message, i can still hear the audio. And I googled lots of this, think this link will be helpful:http://www.codingforums.com/javascript-programming/342454-audio-api-js.html

The createMediaElementSource method should create an object that uses the MediaElementAudioSourceNode interface. Such objects are subject to Cross-Origin Resource Sharing (CORS) restrictions based on the latest draft of the Web Audio API spec. (Note that this restriction doesn't appear to be in the outdated W3C version of the spec.) According to the spec, silence should be played when CORS restrictions block access to a resource, which would explain the "outputs zeroes" message; presumably, zero is equivalent to no sound.

To lift the restriction, the owner of the page at http://morebassradio.no-ip.org:8214/;stream/1 would need to configure their server to output an Access-Control-Allow-Origin header with either a list of domains (including yours) or the * value to lift it for all domains. Given that this stream appears to already be unrestricted, public-facing content, maybe you can convince the owners to output that header. You can test whether the header is being sent by pressing Ctrl+Shift+Q in Firefox to open the Network panel, loading the stream through the address bar, and then inspecting the headers associated with that HTTP request in the Network panel.

Note that they can't use a meta element here since the audio stream is, obviously, not an HTML document; that technique only works for HTML and XHTML documents.

(While you're messing with Firefox panels, you may want to make sure Security errors and warnings are enabled (by clicking the Security button or its arrow) in the Console panel (Ctrl+Shift+K). I'm not sure if there's a corresponding CORS message in Firefox like in Chrome, but there might be. I wasted a bunch of time wondering why a page wasn't working one day while troubleshooting a similar technology, Content Security Policy (CSP), only to find that I had the relevant Firefox messages hidden.)

You shouldn't need to mess with the crossorigin property/attribute unless you set crossorigin = "use-credentials" (JavaScript) or crossorigin="use-credentials" (HTML) somewhere, but you probably didn't do that because that part of the HTML spec isn't finalized yet, and it would almost certainly cause your content to "break" after doing so since credentials would be required at that point.

I'm not familiar with the Web Audio API, so I wasn't able to figure out how to output a MediaElementAudioSourceNode and trigger an error message for my own troubleshooting. If I use createMediaElementSource with an HTMLMediaElement (HTMLAudioElement), the result doesn't seem to be a MediaElementAudioSourceNode based on testing using the instanceof operator even though the spec says it should be if I'm reading it right.

Then in my situation, i get the HTTP response Header:

HTTP/1.1 206 Partial Content
Date: Thu, 02 Jun 2016 06:50:43 GMT
Content-Type: audio/mpeg
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Log, X-Reqid
Access-Control-Max-Age: 2592000
Content-Disposition: inline; filename="653ab5685893b4bf.mp3"
Content-Transfer-Encoding: binary
Last-Modified: Mon, 16 May 2016 02:00:05 GMT
Server: nginx
Cache-Control: public, max-age=31536000
ETag: "FpGQqtcf_s2Ce8W_4Mv6ZqSVkVTK"
X-Log: mc.g;IO:2/304
X-Reqid: 71cAAFQgUBiJMVQU
X-Qiniu-Zone: 0
Content-Range: bytes 0-1219327/1219328
Content-Length: 1219328
Age: 1
X-Via: 1.1 xinxiazai211:88 (Cdn Cache Server V2.0), 1.1 hn13:8 (Cdn Cache Server V2.0)
Connection: keep-alive

Note that "Access-Control-Allow-Origin: *", i think this just the right thing, but i still get the message. Hope it help you.

Answer

I eventually figured out what to do after hours and hours of research and experimenting. There is very little documentation, as of this writing, available online showing how to do this. I hope people will find this helpful.

Understanding CORS:

CORS is an acronym for Cross Origin Resoruce Sharing. CORS is a new standard for sharing/accessing information between different domains. CORS basically is a method of using server headers to tell the browser if it is permitted to access or interact with a specific file on another server. While you can load most things without worrying about CORS (like images, audio, videos, and even other web pages), interaction with these elements requires special permission from the server. In my case, I was attempting to read frequencies from an audio file on another server. In this instance, I was attempting to access information which required authorization from special headers on the server.

Browser support is very good but, if you are supporting older browsers, you may want to see support tables here (http://caniuse.com/#search=cors)

What I did:

Enabled the use of .htaccess (I think you can accomplish the same thing with apache2.conf or 000-default.conf but .htaccess files are much easier to edit and maintain). These files are used to set headers and settings for apache. I enabled the use of .htaccess files by going to /etc/apache2/ and edited apache2.conf. Make sure your entry matches the following:

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
</Directory>

I set the headers in my .htaccess file to allow access from Codepen. Create a .htaccess file in the same directory as the file you want to share. You only want to share what you have to or you might create a security risk. Type this in your .htaccess file:

Header set Access-Control-Allow-Origin: "http://websiteWantingToAccessYourFile.com".

Save your file. Restart Apache with this command sudo service apache2 restart. Enter your password if prompted. With the audio, I added the crossorigin="anonymous" attribute. You can read more about CORS settings (crossorigin) here (https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) I imagine you can set this with ajax and xhr requests. Different versions of apache may have different file names or standards. Check to make sure this is correct for your version. I am running Apache 2.4.18 on my Ubuntu server.

Please tell me if this can be improved. I have spent a lot of time understanding this but I am not an expert. Post your questions or suggestions in the comments. :)

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.