2

I'm getting a Content Security Policy directive violation when trying to play an mp3 from a base64 encoded string.

Context: I'm developing a Chrome App that I convert to an Android App using Apache Cordova. When running the Chrome App on my computer everything works like a charm, but when running the App under Android I see the following error in the console:

Refused to load media from 'data:audio/mp3;base64,//tQxAAAAA…AAAAD/' because it violates the following Content Security Policy directive: "media-src *".

The code is pretty simple:

var sound = 'data:audio/mp3;base64,//tQxAAAAAAAAAAAAAA…AAD/';
new Audio(sound).play();

As far as I can see I can not loosen the restriction "media-src *". I added this to my index.html:

<meta http-equiv="Content-Security-Policy" content="media-src *">

And these (just for testing) to my config.xml:

<allow-navigation href="*"/>
<allow-intent href="*"/>

But no success...

I also tried what was described here.

function onSuccess() {                                  
  console.log('success', arguments);                    
}                                                       
function onError() {                                    
  console.log('error', arguments);                      
}                                                       
function onStatus() {                                   
  console.log('status', arguments);                     
}                                                       
var player = new Media(sound, onSuccess, onError, onStatus);
console.log('Using cca Media');                         
player.play()

Output:

Using cca Media
status { 0: 1 }
error { 0: { code: 1 } }

So this does not seem to be suitable for playing music from a base64 string because I see this when checking logcat:

I/MediaPlayerService(28744): [setDataSource] setDataSource(/storage/sdcard0/data:audio/mp3;base64,//tQxAAAAAA…bR+0Ne
D/MediaPlayerFactory(28744): getPlayerType(): using url, check for DRM protected midi.
D/DrmMtkUtil/DrmUtil(28744): checkDcf ----> path [/storage/sdcard0/data:audio/mp3;base64,//tQxAAAAAA…t5A2r/
V/DrmMtkUtil/DrmUtil(28744): checkExistence ----> [/storage/sdcard0/data:audio/mp3;base64,//tQxAAAAAA…Vt5A2r
E/DrmMtkUtil/DrmUtil(28744): checkExistence failed, reason [File name too long]
E/DrmMtkUtil/DrmUtil(28744): checkDcf: file does not exist.
D/MediaPlayerService(28744): player type = 4
E/DrmMtkUtil(28744): [ERROR]isDcf() : failed to dup fd, reason [File name too long]
I/MediaPlayerService(28744): [setDataSource] setDataSource(/storage/sdcard0/data:audio/mp3;base64,//tQxAAAAAAA…txIbR+0Ne
I/MediaPlayerService(28744): [prepareAsync] [45] prepareAsync
D/NuPlayer(28744): kWhatPrepare, source type = 0
E/        (28744): Failed to open file '/storage/sdcard0/data:audio/mp3;base64,//tQxAAAAA…5A2r/

It assumes the source is a filename. I also did not find anything in the documentation to force it to interpret it as a data URI.

In fact this question was my hottest lead, but the resolution is not really clear to me since it looks he is (eventually) successfully doing it just the way I have unsuccessfully tried it...

So, what is the proper way to play audio from a base64 encoded string in Android?

Heye
  • 603
  • 6
  • 14
  • The important lines looks like `E/DrmMtkUtil/DrmUtil(28744): checkExistence failed, reason [File name too long]` and `E/DrmMtkUtil(28744): [ERROR]isDcf() : failed to dup fd, reason [File name too long]`, look into converting _Base64_ to _Blob_, generating an _Object URL_ from the _Blob_ (this URL will be much shorter because it's just a hash for the file on disc), playing the file at the _Object URL_ – Paul S. Jun 05 '16 at 23:23
  • That could work, but something is still wrong: `[ERROR]isDcf() : failed to dup fd, reason [No such file or directory]` and more specifically `Failed to open file '/storage/sdcard0/blob:file%3A///4cdb5ef6-db62-4bd1-bb2b-0eafd8303a62'. (No such file or directory) ` The URL I'm generating is `blob:file%3A///4cdb5ef6-db62-4bd1-bb2b-0eafd8303a62`. I feel like the prefixing (done by the Media function somewhere in the process) with `/storage/sdcard0/` is causing problems here, or should it be like that? – Heye Jun 06 '16 at 00:03
  • The linked question uses mimetype "audio/mpeg" for the data URL (not "audio/mp3"), backed up by this question on [Which mime type should I use for mp3](http://stackoverflow.com/questions/10688588/which-mime-type-should-i-use-for-mp3). – traktor Jun 06 '16 at 00:26
  • That sounded promising, but also with mimetype `audio/mpeg` it still gives me the CSP violation: `Refused to load media from 'data:audio/mpeg;base64,//tQxAAA…AAAAD/' because it violates the following Content Security Policy directive: "media-src *".` – Heye Jun 06 '16 at 07:17
  • `Failed to open file '/storage/sdcard0/blob:file%3A///4cdb5ef`... means that the URI is being treated as a path or is not on the node correctly (should start with the `blob:` protocol – Paul S. Jun 06 '16 at 18:53
  • Yes, I think that is the problem. The documentation describes the field as "src: A URI containing the audio content."[1]. So I would expect it to be able to deal with `data:` and `blob:` URIs. [1]: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-media/index.html#media – Heye Jun 07 '16 at 06:09
  • * But for some reason it prepends `/storage/sdcard0` to the path. – Heye Jun 07 '16 at 06:18

1 Answers1

3

Did you try adding data: to media src? * does not cover all values like you may think.

oreoshake
  • 4,712
  • 1
  • 31
  • 38
  • Ahh okay, I now tried ``. Which is correctly interpreted when running it as a Chrome App on my Desktop Computer. But when deploying to my phone it still says it violates the directive `"media-src *"`. So on my phone it is following a different directive. – Heye Jun 07 '16 at 06:10