13

I created a ContentProvider. It exports files within my assets/ directory. I'm using content:// urls to access the exported content in a WebView.

The following HTML works as expected:

<img src="content://<provider-name>/test.jpg">

I'm trying to use the content provider for mp3 audio files:

<div id='player'></div>
<script>
  url = "content://<provider-name>/test.mp3";
  var audio = document.createElement('audio');
  audio.src = url;
  audio.controls = "controls";
  document.getElementById("player").appendChild(audio);
</script>

I'm getting the following error message.

E/MediaPlayer(24120): Unable to to create media player
E/HTML5Audio(24120): couldn't load the resource: content://.../test.mp3 exc: java.io.IOException: setDataSource failed.: status=0x80000000

I tried the Android SDK 8 and 10 without success. I'm not seeing any access to my ContentProvider in the log. It looks like accessing content from audio-tags is not possible within a WebView. It seems strange, since the following code works as expected:

MediaPlayer player = MediaPlayer.create(this, 
    Uri.parse("content://<provider-name>/test.mp3")
);
player.start();

How can I play audio files from a ContentProvider within a WebView?

EAGLE
  • 586
  • 1
  • 6
  • 15
dividuum
  • 286
  • 1
  • 6
  • Strolling other answers, I don't think it would help, but what about trying to add the `uses-permission android:name="android.permission.INTERNET" />` to your manifest. Just a common answer across so. I shall look more. – FabianCook May 27 '13 at 10:12
  • Maybe this might help. http://helpmeco.de/2012/2/serving-android-webview-resources-with-content-providers – FabianCook May 27 '13 at 10:15
  • @SmartLemon: nope, that's pretty much what I've done so far. Again, as dividuum, images are loaded OK, JS runs fine: just audio resources fail to load. – Mick F May 27 '13 at 10:18

4 Answers4

4

The short answer is no, you can't use content:// as a source for an audio element.

The error you are getting comes from the HTML5Audio setDataSource method, which if you look at the source code, calls MediaPlayer setDataSource with the audio url. And if you look at the documentation for the MediaPlayer class, it only supports file paths and http/rtsp urls.

I think your best bet is to save your audio content to a file path and use a file: url to access it.

However, if I remember correctly, you will also need to make the file world readable in order for the MediaPlayer code to access it. This requires using the private android.os.FileUtils class with code like this:

void makeFileReadable(String filename) {
  try {
    Class fileUtils = Class.forName("android.os.FileUtils");
    Method setPermissions = fileUtils.getMethod("setPermissions", String.class,
     int.class, int.class, int.class);
    setPermissions.invoke(fileUtils, filename, 0775, -1, -1);
  }
  catch (Exception ex) {
  }
}

775 is the equivalent of rwxrwxr-x which may be more permissive than necessary, so you may want to try experimenting with less permissive values. Also note that you'll likely need to set the permissions on the directory containing the file, and that directory's parent, etc. - not just the file itself.

James Holderness
  • 22,721
  • 2
  • 40
  • 52
2

Here are some things I found helpful:

Just to clarify, File paths

Is there a path similar to file:///android_asset/ that points to the apps directory?

content:// - for already exported media on sdcard/

file:///android_asset - for items in your assets/ folder

Obtaining the assets:

Pulling assets using AssetManager:

How to get URI from an asset File?

Putting sound in WebView from assets programmatically using MediaPlayer:

Sound in Webview

Android WebView playing audio with javascript

Using HTML5:

Html Audio in Android Webview

Here are few methods you have not tried. Lately I have been working with alot of WebViews and JavaScript as well, so maybe one of these other methods will do the trick.

Regards,

Community
  • 1
  • 1
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
  • Thanks for your answer. content:// works fine for images, not for medias, as mentioned in the question. I'll need to give a try to the URL interception and launching my own MediaPlayer (sounds like a pain in the ass though: how to control seeking and have a good memory management this way?). – Mick F May 29 '13 at 09:11
  • I am not sure but I have found that others have used MediaPlayer in order to achieve this. – Jared Burrows May 29 '13 at 13:19
1

Option #1: Manifest file.

Check that you have the correct permission in your manifest file:

<uses-permission android:name="android.permission.INTERNET" />

Option #2: Bad or corrupted audio file.

Check if you can play the file with Android's Media Player.

Option #3: Reading permissions

Maybe, the file is not actually readable by the player. In this case, using a FileDescriptor should work. I've read somewhere (sorry, I can't remember where) that some issues with the same exception have been reported with setDataSource(FileDescriptor fd). Try using setDataSource(FileDescriptor fd, long offset, long length), as it seems to solve the problem.

Alejandro Colorado
  • 6,034
  • 2
  • 28
  • 39
0

I managed to get this working after much consternation. For some reason a call to your content provider from a webView (which uses the MediaPlayer) for an mp3 file does not call openAssetFile, but rather it calls openFile. (not sure if the provider handles this routing). This problem appears to have been fixed in 4.2+

The solution for older versions which worked for me was to override openFile in your content provider thus:

@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode){
    //your asset reading code that works for other file types goes here.
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode){
    try {
        AssetFileDescriptor afd = openAssetFile(uri, mode);
        return afd.getParcelFileDescriptor();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}
Leonard Feehan
  • 482
  • 3
  • 13