MediaPlayer setDataSource failed with status=0x80000000 for Ringtone set by filepath on 2.3.4
Asked Answered
N

6

25

Title says most of it.

My application has been playing ringtones pointed by uri like content://media/internal/audio/media/387 or content://media/external/audio/media/1655 (for custom ringtones on SDcard I believe) using both setDataSource(fileInfo) and setDataSource(mContext, Uri.parse(fileInfo)).

In each case I have received logs with information about setDataSource failed.: status=0x80000000 exception on phones using Android 4.x (different versions).

Seeing that the error happens only to ringtones pointed by content uri, but not to single files pointed by path, I have decided to use paths for ringtones as well which fixed problem on above phones (while still using setDataSource(mContext, Uri.parse(fileInfo)) )

It has however started problems on phones with Android 2.3.4-2.3.6 (not on mine 2.3.3 though):

  • I have received few logs with exception: setDataSource failed.: status=0x80000000 for files with paths like /system/media/audio/ringtones/TwirlAway.ogg
  • I have also received a log about MediaPlayer.onErrorListener.onError(int what, int extra) method call with what=1 and extra=-2147483648, which, from what I know, suggest either that file is missing or it is corrupted. However I perform

    File file = new File(fileInfo);
    if (!file.exists())
    

check in such situation and it returned that file does exist - is it corrupted then? Highly unlikely for music file in internal memory.

To sum up:

  • works with setDataSource("content://media/internal/audio/media/52")
  • throws exception: setDataSource failed.: status=0x80000000 for setDataSource(mContext, "/system/media/audio/ringtones/TwirlAway.ogg")

Interestingly, first few lines of setDataSource(Context context, Uri uri, Headers headers) method which is called by setDataSource(Context context, Uri uri) are (from GrepCode source for 2.3.4):

 String scheme = uri.getScheme();
     if(scheme == null || scheme.equals("file")) {
         setDataSource(uri.getPath());
         return;
     }

So, after all, it just fails for setDataSource("/system/media/audio/ringtones/TwirlAway.ogg"). I have taken paths to ringtones from uris by using:

private static String getRingtonePathFromContentUri(Context context,
        Uri contentUri) {

    String[] proj = { MediaStore.Audio.Media.DATA };
    Cursor ringtoneCursor = context.getContentResolver().query(contentUri,
            proj, null, null, null);
    ringtoneCursor.moveToFirst();
    return ringtoneCursor.getString(ringtoneCursor
            .getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
}

Any ideas what can be causing error throwing? Maybe those are some issues caused by lack of reading permissions? I guess source code for native setDataSource(String path) function would help a lot, but I wasn't able to find it.

Neom answered 6/5, 2013 at 9:17 Comment(0)
N
15

Answer by Lorne below was most helpful when dealing with this problem.

For anyone else struggling with it, here is the code that I have been using for over 6 months now with errors almost not reported anymore.

fileinfo can be both of below (examples):

/system/media/audio/alarms/Walk_in_the_forest.ogg

content://media/internal/audio/media/20

public static void setMediaPlayerDataSource(Context context,
        MediaPlayer mp, String fileInfo) throws Exception {

    if (fileInfo.startsWith("content://")) {
        try {
            Uri uri = Uri.parse(fileInfo);
            fileInfo = getRingtonePathFromContentUri(context, uri);
        } catch (Exception e) {
        }
    }

    try {
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
            try {
                setMediaPlayerDataSourcePreHoneyComb(context, mp, fileInfo);
            } catch (Exception e) {
                setMediaPlayerDataSourcePostHoneyComb(context, mp, fileInfo);
            }
        else
            setMediaPlayerDataSourcePostHoneyComb(context, mp, fileInfo);

    } catch (Exception e) {
        try {
            setMediaPlayerDataSourceUsingFileDescriptor(context, mp,
                    fileInfo);
        } catch (Exception ee) {
            String uri = getRingtoneUriFromPath(context, fileInfo);
            mp.reset();
            mp.setDataSource(uri);
        }
    }
}

private static void setMediaPlayerDataSourcePreHoneyComb(Context context,
        MediaPlayer mp, String fileInfo) throws Exception {
    mp.reset();
    mp.setDataSource(fileInfo);
}

private static void setMediaPlayerDataSourcePostHoneyComb(Context context,
        MediaPlayer mp, String fileInfo) throws Exception {
    mp.reset();
    mp.setDataSource(context, Uri.parse(Uri.encode(fileInfo)));
}

private static void setMediaPlayerDataSourceUsingFileDescriptor(
        Context context, MediaPlayer mp, String fileInfo) throws Exception {
    File file = new File(fileInfo);
    FileInputStream inputStream = new FileInputStream(file);
    mp.reset();
    mp.setDataSource(inputStream.getFD());
    inputStream.close();
}

private static String getRingtoneUriFromPath(Context context, String path) {
    Uri ringtonesUri = MediaStore.Audio.Media.getContentUriForPath(path);
    Cursor ringtoneCursor = context.getContentResolver().query(
            ringtonesUri, null,
            MediaStore.Audio.Media.DATA + "='" + path + "'", null, null);
    ringtoneCursor.moveToFirst();

    long id = ringtoneCursor.getLong(ringtoneCursor
            .getColumnIndex(MediaStore.Audio.Media._ID));
    ringtoneCursor.close();

    if (!ringtonesUri.toString().endsWith(String.valueOf(id))) {
        return ringtonesUri + "/" + id;
    }
    return ringtonesUri.toString();
}

public static String getRingtonePathFromContentUri(Context context,
        Uri contentUri) {
    String[] proj = { MediaStore.Audio.Media.DATA };
    Cursor ringtoneCursor = context.getContentResolver().query(contentUri,
            proj, null, null, null);
    ringtoneCursor.moveToFirst();

    String path = ringtoneCursor.getString(ringtoneCursor
            .getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));

    ringtoneCursor.close();
    return path;
}
Neom answered 13/11, 2014 at 9:32 Comment(8)
I've tried to solve this problem for almost a month. Our app is even an alarm app, which should play the music or ringtone perfectly in the morning but until now there are so many crashes when playing the music.Laughry
I've been frustrated because of this problem and you saved my month!Laughry
how to work with path such as /storage/emulated/0/IDM/Music/xxx.mp3 ?? Even this is failing on this.Paint
@Paint what seems to be a problem? Above solution is still working for me. Maybe your file is corrupted or not found at this location?Neom
This code won't work when your file path has spaces in it which are represented by %20 (e.g. file:///storage/emulated/0/Music/Artist%20(feat.%20ArtistPart1%20ArtistPart2).mp3), as the uri encode will replace %20 with spaces but afterwards the setDataSource won't work. If I simply remove the Uri.encode it works, but at what cost? I haven't seen a situation where the code without the encode part doesn't work but my test cases are limited.Gloat
@Paint can you share your fix?Sturmabteilung
@MikeHoller I don't remember solution exactly and I don't have access to the source now. The solution was a fallback kind of solution first try the URI if it doesn't give a valid file descriptor then use the projection. However, the above code does work as Koger said, play around with it, you will get the solution working.Paint
Best answer so far! Thanks a ton for the help!Vachel
R
6

You have to explicit set the length of your file. Use the overloaded method:
AssetFileDescriptor afd = ctx.getAssets().openFd([your asset name]); mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

Rior answered 15/4, 2016 at 21:44 Comment(1)
Thank you, never thought this was causing the error! I used to call the overloaded method above but this time I called the simpler one without thinking..Septavalent
F
4

There was a change in the behaviour of setDataSource(String path) due to a bug fix in Android 4.1.1. In 4.1.1 or later you need to use a local path (without protocol). However, on 4.0.4 and earlier you needed to use a URI (e.g. with file:// protocol).

Here is an incomplete code snippet that should illustrate the workaround:

// as of 4.1.1 (JELLY_BEAN) we need to use a local path (without protocol)
// on 4.0.4 and earlier we needed a URI (with file:// protocol)
final String cachedFile = android.os.Build.VERSION.SDK_INT >= 16 // android.os.Build.VERSION_CODES.JELLY_BEAN
                        ? getCacheFilePath(file)
                        : getCacheFileUri(file);


// for the purpose of this example 
// assume cacheFolder is a String and getCacheFile returns a String

public String getCacheFilePath(String file) {
    return cacheFolder + getCacheFile(file);
}

public String getCacheFileUri(String file) {
    return "file://" + cacheFolder + getCacheFile(file);
}
Freak answered 3/3, 2014 at 16:58 Comment(0)
O
2

This may be happening because of file format you are trying to play or compress. I was compressing a mp4 file which works well but when I compress a mov file the application crashed giving the setDataSource failed exception.

Oarsman answered 20/2, 2019 at 12:39 Comment(1)
That's true. It has mainly to do with file formats. Working with video files, I figure that out of the following video formats: AVI, MPG/MPEG, MOV, mov, mp4, m4v, flv, WMV, I noticed that AVI, MPG/MPEG, and WMV threw an exception for me every time. Better to exclude them before running the method and wrap it with a try-catch.Catkin
T
0

I had the same error, when I was trying to play a .wav file. Let´s make an example:

 private void start_player(){
// create raw folder inside the res folder if not present
MediaPlayer mPlayer = MediaPlayer.create(activity, R.raw.your_wave_audio_file);
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.setOnCompletionListener(new OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                mp.release();
               // Your Stuff
            }
        });  
         mPlayer.start();
     }
    }

I too got the status=0x80000000 error. In my case the solution was to re-encode the audio file (for example to 16-BIT PCM for a .wav file) and everything worked as expected.

Tenant answered 5/5, 2014 at 17:40 Comment(0)
M
-1
MediaPlayer mPlayer = MediaPlayer.create(activity, R.raw.your_wave_audio_file);
    mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

You can't do it, because prepare was called in create function, therefore you can't change Audio Stream Type after.

Below code is worked fine for me:

sMediaPlayer = new MediaPlayer();
sMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
AssetFileDescriptor assetFileDescriptor = context.getResources().
         openRawResourceFd(R.raw.cool_song);

 if(assetFileDescriptor == null) return;

 try {
    sMediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
                               assetFileDescriptor.getStartOffset(), 
                               assetFileDescriptor.getLength());
    assetFileDescriptor.close();

    sMediaPlayer.setOnCompletionListener(new OnCompletionListener() {           
        @Override
        public void onCompletion(MediaPlayer mp) {
            if(sMediaPlayer != null){
                sMediaPlayer.release();
                sMediaPlayer = null;
            }
        }
    });

    sMediaPlayer.setOnPreparedListener(new OnPreparedListener() {               
        @Override
        public void onPrepared(MediaPlayer mp) {
            sMediaPlayer.start();                   
        }
    });
    sMediaPlayer.prepare();

} catch (IllegalArgumentException e) {
    HelpFunctions.showLog("ERROR = " + e);
} catch (IllegalStateException e) {
    HelpFunctions.showLog("ERROR = " + e);
} catch (IOException e) {
    HelpFunctions.showLog("ERROR = " + e);
}
Militarist answered 12/11, 2014 at 2:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.