MediaPlayer setDataSource 失败,状态 = 0x80000000 为 2.3.4 上的文件路径设置的铃声

Posted

技术标签:

【中文标题】MediaPlayer setDataSource 失败,状态 = 0x80000000 为 2.3.4 上的文件路径设置的铃声【英文标题】:MediaPlayer setDataSource failed with status=0x80000000 for Ringtone set by filepath on 2.3.4 【发布时间】:2013-04-30 00:29:19 【问题描述】:

标题说明了大部分内容。

我的应用程序一直在使用setDataSource(fileInfo)setDataSource(mContext, Uri.parse(fileInfo)) 播放由uri 指向的铃声,例如content://media/internal/audio/media/387content://media/external/audio/media/1655(我相信SD 卡上的自定义铃声)。

在每种情况下,我都收到了有关使用 android 4.x(不同版本)的手机上的 setDataSource failed.: status=0x80000000 异常信息的日志。

看到错误只发生在内容 uri 指向的铃声上,而不是路径指向的单个文件上,我决定使用铃声路径以及修复上述手机上的问题(同时仍在使用setDataSource(mContext, Uri.parse(fileInfo))

然而,它在 Android 2.3.4-2.3.6 的手机上开始出现问题(虽然不是我的 2.3.3):

我收到的日志很少,但有以下例外:setDataSource failed.: status=0x80000000 文件的路径类似于/system/media/audio/ringtones/TwirlAway.ogg

我还收到了关于 MediaPlayer.onErrorListener.onError(int what, int extra) 方法调用的日志,其中包含 what=1extra=-2147483648,据我所知,这表明该文件丢失或已损坏。但是我执行

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

在这种情况下检查并返回该文件确实存在 - 那么它是否已损坏?内存中的音乐文件不太可能。

总结一下:

setDataSource("content://media/internal/audio/media/52")一起工作 抛出异常:setDataSource failed.: status=0x80000000 for setDataSource(mContext, "/system/media/audio/ringtones/TwirlAway.ogg")

有趣的是,setDataSource(Context context, Uri uri) 调用的 setDataSource(Context context, Uri uri, Headers headers) 方法的前几行是 (from GrepCode source for 2.3.4):

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

所以,毕竟setDataSource("/system/media/audio/ringtones/TwirlAway.ogg") 失败了。我已经通过使用从uris获取铃声的路径:

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));

任何想法可能导致错误抛出?也许这些是由于缺乏阅读权限引起的一些问题? 我想本机 setDataSource(String path) 函数的源代码会有很大帮助,但我找不到它。

【问题讨论】:

【参考方案1】:

以下 Lorne 的回答在处理此问题时最有帮助。

对于其他苦苦挣扎的人,这是我已经使用了 6 个月以上的代码,几乎不再报告错误。

fileinfo 可以是以下两者(示例):

/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;

【讨论】:

我已经尝试解决这个问题将近一个月了。我们的应用程序甚至是一个闹钟应用程序,它应该在早上完美地播放音乐或铃声,但直到现在播放音乐时出现很多崩溃。 因为这个问题我很沮丧,你救了我的 如何使用 /storage/emulated/0/IDM/Music/xxx.mp3 等路径?即使这是失败的。 @jeevs 似乎有什么问题?以上解决方案仍然对我有用。也许您的文件已损坏或在此位置找不到? 当您的文件路径中包含由 %20 表示的空格时,此代码将不起作用(例如 file:///storage/emulated/0/Music/Artist%20(feat.% 20ArtistPart1%20ArtistPart2).mp3),因为 uri 编码会将 %20 替换为空格,但之后 setDataSource 将不起作用。如果我只是删除 Uri.encode 它可以工作,但代价是什么?我还没有看到没有编码部分的代码不起作用但我的测试用例有限的情况。【参考方案2】:

您必须明确设置文件的长度。使用重载方法:AssetFileDescriptor afd = ctx.getAssets().openFd([your asset name]); mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

【讨论】:

谢谢,没想到是这个错误!之前我调用了上面的重载方法,但这次我不假思索地调用了更简单的方法..【参考方案3】:

由于 Android 4.1.1 中的错误修复,setDataSource(String path) 的行为发生了变化。在 4.1.1 或更高版本中,您需要使用本地路径(无协议)。但是,在 4.0.4 和更早版本上,您需要使用 URI(例如,使用 file:// 协议)。

这是一个不完整的代码 sn-p,应该说明解决方法:

// 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);

【讨论】:

【参考方案4】:

这可能是因为您尝试播放或压缩的文件格式。我正在压缩一个运行良好的 mp4 文件,但是当我压缩一个 mov 文件时,应用程序崩溃了,出现了 setDataSource 失败异常。

【讨论】:

确实如此。它主要与文件格式有关。处理视频文件时,我发现以下视频格式:AVI、MPG/MPEG、MOV、mov、mp4、m4v、flv、WMV,我注意到 AVI、MPG/MPEG 和 WMV 每次都对我抛出异常时间。最好在运行方法之前排除它们并用 try-catch 包装它。【参考方案5】:

我在尝试播放 .wav 文件时遇到了同样的错误。举个例子吧:

 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();
     
    

我也遇到了 status=0x80000000 错误。在我的情况下,解决方案是重新编码音频文件(例如,将 .wav 文件编码为 16 位 PCM)并且一切都按预期工作。

【讨论】:

【参考方案6】:
MediaPlayer mPlayer = MediaPlayer.create(activity, R.raw.your_wave_audio_file);
    mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

你不能这样做,因为在create函数中调用了prepare,因此你不能改变音频流类型。

下面的代码对我来说很好用:

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);

【讨论】:

以上是关于MediaPlayer setDataSource 失败,状态 = 0x80000000 为 2.3.4 上的文件路径设置的铃声的主要内容,如果未能解决你的问题,请参考以下文章

Android MediaPlayer setDataSource failed

Caused by:java.lang.IllegalStateException at android.media.MediaPlayer._setDataSource(Native Method)

MediaPlayer.setDataSource 导致有效文件的 IOException

Android MediaPlayer 无法 SetDataSource()

MediaPlayer 播放本地视频源码流程-setDataSource

Android Multimedia框架总结MediaPlayer中创建到setDataSource过程