Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading audio via a Blob URL fails in Safari

Following code works in Chrome (22.0) but not in Safari (6.0)

<!DOCTYPE html>
<html>
<head>
<script>
function onGo(e) {
  var fr = new FileReader();
  var file = document.getElementById("file").files[0];
  fr.onload = function(e) {
      var data = new Uint8Array(e.target.result);
      var blob = new Blob([data], {type: 'audio/mpeg'});
      var audio = document.createElement('audio'); 
      audio.addEventListener('loadeddata', function(e) { 
          audio.play();
        }, false);
      audio.addEventListener('error', function(e) {
          console.log('error!', e);
        }, false);
      audio.src = webkitURL.createObjectURL(blob);    
    };
  fr.readAsArrayBuffer(file);
}
</script>
</head>
<body>
  <input type="file" id="file" name="file" />
  <input type="submit" id="go" onclick="onGo()" value="Go" />
</body>
</html>

In Safari, neither callback (loadeddata nor error) is called. The content used is an mp3 file, which is normally played back with audio tag. Is there any special care needed for Safari?

like image 817
kuu Avatar asked Nov 05 '12 12:11

kuu


2 Answers

Many years later, I believe the example in the OP should work just fine. As long as you somehow set the mime type when creating the blob, like the OP does above with the type property of the options passed in:

new Blob([data], {type: 'audio/mpeg'});

You could also use a <source> element inside of an audio element and set the type attribute of the <source> element. I have an example of this here:

https://lastmjs.github.io/safari-object-url-test

And here is the code:

const response = await window.fetch('https://upload.wikimedia.org/wikipedia/commons/transcoded/a/ab/Alexander_Graham_Bell%27s_Voice.ogg/Alexander_Graham_Bell%27s_Voice.ogg.mp3');

const audioArrayBuffer = await response.arrayBuffer();
const audioBlob = new Blob([audioArrayBuffer]);
const audioObjectURL = window.URL.createObjectURL(audioBlob);

const audioElement = document.createElement('audio');

audioElement.setAttribute('controls', true);
document.body.appendChild(audioElement);

const sourceElement = document.createElement('source');

audioElement.appendChild(sourceElement);

sourceElement.src = audioObjectURL;
sourceElement.type = 'audio/mp3';

I prefer just setting the mime type of the blob when creating it. The <source> element src attribute/property cannot be updated dynamically.

like image 118
lastmjs Avatar answered Oct 10 '22 20:10

lastmjs


I have the same problem, and I spend a couple days troubleshooting this already. As pwray mentioned in this other post, Safari requires file extensions for media requests:

HTML5 Audio files fail to load in Safari

I tried to save my blob to a file, named it file.mp3 and Safari was able to load the audio that way, but after I renamed the file to have no extension (just "file"), it didn't load. When I tried the url created from the blob in another tab in Safari:

url = webkitURL.createObjectURL(blob);

it download a file right away called "unknown", but when I tried the same thing in Chrome (also on Mac), it showed the content of the file in the browser (mp3 files start with ID3, then a bunch of non-readable characters). I couldn't figure out yet how I could force the url made of blob to have an extension, because usually it looks like this:

blob:https://example.com/a7e38943-559c-43ea-b6dd-6820b70ca1e2

so the end of it looks like a session variable.

This is where I got stuck and I would really like to see a solution from some smart people here. Thanks, Steven

like image 21
Steven Avatar answered Oct 10 '22 20:10

Steven