Android MediaPlayer AudioStream AudioFlinger 服务器死机!,致命信号 11

Posted

技术标签:

【中文标题】Android MediaPlayer AudioStream AudioFlinger 服务器死机!,致命信号 11【英文标题】:Android MediaPlayer AudioStream AudioFlinger server died!, Fatal signal 11 【发布时间】:2013-03-09 16:38:45 【问题描述】:

我有两个片段(左侧和右侧),并在左侧片段中获取 Radiostreams 列表。通过单击这些流之一,正确的片段应更改流的名称并开始使用给定的 uri 播放流。

2 个问题:

    一些无线电流不是最新的,所以它们中的很多不再工作了。问题是,这会导致我的应用程序强制关闭!我做了错误处理,但在调用这样的流后我得到:

03-20 14:23:28.192: A/libc(1021): 致命信号 11 (SIGSEGV) 在 0x00000000(代码=1)

03-20 14:23:28.192:W/AudioSystem(1021):AudioFlinger 服务器死机!

03-20 14:23:28.192:W/IMediaDeathNotifier(1021):媒体服务器死了

03-20 14:23:28.192: E/MediaPlayer(1021): 错误 (100, 0)

03-20 14:23:28.192: I/ServiceManager(1021): 等待服务 media.audio_flinger...

03-20 14:23:28.752: I/dalvikvm(1021): threadid=3: 对信号 3 做出反应

03-20 14:23:28.782: I/dalvikvm(1021): 将堆栈跟踪写入 '/data/anr/traces.txt'

03-20 14:23:29.192: I/ServiceManager(1021): 等待服务 media.audio_flinger...

我不知道为什么。还有其他方法可以进行错误处理吗?或者有没有办法在调用 mediaPlayer.setDataSource(uri) 之前检查所有流以避免准备 defekt uris? (最后见我的代码)

    我正在用遥控器控制左侧的 ListFragment。当我尝试从一个频道快速切换到另一个频道时,一切都非常滞后。似乎 Mediaplayer 的重新实例化需要很长时间。当我不重新实例化时,当我再次调用 mediaPlayer.setDataSource(..) 时会出现运行时错误。有没有办法在一个 MediaPlayer 对象上调用 .setDataSource 两次?

这是我的代码: 我的 MediaPlayer Wrapper 类:

package net.smart4life.tvplay.model;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.util.Log;

/**
 * A wrapper class for @link android.media.MediaPlayer.
 * <p>
 * Encapsulates an instance of MediaPlayer, and makes a record of its internal
 * state accessible via a @link MediaPlayerWrapper#getState() accessor.
 */
public class MediaPlayerStateWrapper 

    private static String tag = "MediaPlayerWrapper";
    private MediaPlayer mPlayer;
    private State currentState;
    private MediaPlayerStateWrapper mWrapper;

    public MediaPlayerStateWrapper() 
        mWrapper = this;
        mPlayer = new MediaPlayer();
        currentState = State.IDLE;
        mPlayer.setOnPreparedListener(mOnPreparedListener);
        mPlayer.setOnCompletionListener(mOnCompletionListener);
        mPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
        mPlayer.setOnErrorListener(mOnErrorListener);
        mPlayer.setOnInfoListener(mOnInfoListener);
    

    /* METHOD WRAPPING FOR STATE CHANGES */
    public static enum State 
        IDLE, ERROR, INITIALIZED, PREPARING, PREPARED, STARTED, STOPPED, PLAYBACK_COMPLETE, PAUSED;
    

    public void setDataSource(String path) 
        if (currentState == State.IDLE) 
            try 
                mPlayer.setDataSource(path);
                currentState = State.INITIALIZED;
             catch (IllegalArgumentException e) 
                e.printStackTrace();
             catch (IllegalStateException e) 
                e.printStackTrace();
             catch (IOException e) 
                e.printStackTrace();
            
         else
            throw new RuntimeException();
    

    public void prepareAsync() 
        Log.d(tag, "prepareAsync()");
        if (EnumSet.of(State.INITIALIZED, State.STOPPED).contains(currentState)) 
            mPlayer.prepareAsync();
            currentState = State.PREPARING;
         else
            throw new RuntimeException();
    

    public boolean isPlaying() 
        Log.d(tag, "isPlaying()");
        if (currentState != State.ERROR) 
            return mPlayer.isPlaying();
         else
            throw new RuntimeException();
    

    public void seekTo(int msec) 
        Log.d(tag, "seekTo()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.PLAYBACK_COMPLETE).contains(currentState)) 
            mPlayer.seekTo(msec);
         else
            throw new RuntimeException();
    

    public void pause() 
        Log.d(tag, "pause()");
        if (EnumSet.of(State.STARTED, State.PAUSED).contains(currentState)) 
            mPlayer.pause();
            currentState = State.PAUSED;
         else
            throw new RuntimeException();
    

    public void start() 
        Log.d(tag, "start()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.PLAYBACK_COMPLETE).contains(currentState)) 
            mPlayer.start();
            currentState = State.STARTED;
         else
            throw new RuntimeException();
    

    public void stop() 
        Log.d(tag, "stop()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.STOPPED,
                State.PAUSED, State.PLAYBACK_COMPLETE).contains(currentState)) 
            mPlayer.stop();
            currentState = State.STOPPED;
         else
            throw new RuntimeException();
    

    public void reset() 
        Log.d(tag, "reset()");
        mPlayer.reset();
        currentState = State.IDLE;
    

    /**
     * @return The current state of the mediaplayer state machine.
     */
    public State getState() 
        Log.d(tag, "getState()");
        return currentState;
    

    public void release() 
        Log.d(tag, "release()");
        mPlayer.release();
    

    /* INTERNAL LISTENERS */
    private OnPreparedListener mOnPreparedListener = new OnPreparedListener() 

        @Override
        public void onPrepared(MediaPlayer mp) 
            Log.d(tag, "on prepared");
            currentState = State.PREPARED;
            mWrapper.onPrepared(mp);
            mPlayer.start();
            currentState = State.STARTED;
        
    ;
    private OnCompletionListener mOnCompletionListener = new OnCompletionListener() 

        @Override
        public void onCompletion(MediaPlayer mp) 
            Log.d(tag, "on completion");
            currentState = State.PLAYBACK_COMPLETE;
            mWrapper.onCompletion(mp);
        
    ;
    private OnBufferingUpdateListener mOnBufferingUpdateListener = new OnBufferingUpdateListener() 

        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) 
            Log.d(tag, "on buffering update");
            mWrapper.onBufferingUpdate(mp, percent);
        
    ;
    private OnErrorListener mOnErrorListener = new OnErrorListener() 

        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) 
            Log.d(tag, "on error");
            currentState = State.ERROR;
            mWrapper.onError(mp, what, extra);
            return false;
        
    ;
    private OnInfoListener mOnInfoListener = new OnInfoListener() 

        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) 
            Log.d(tag, "on info");
            mWrapper.onInfo(mp, what, extra);
            return false;
        
    ;

    /* EXTERNAL STUBS TO OVERRIDE */
    public void onPrepared(MediaPlayer mp) 
    

    public void onCompletion(MediaPlayer mp) 
    

    public void onBufferingUpdate(MediaPlayer mp, int percent) 
    

    boolean onError(MediaPlayer mp, int what, int extra) 
        // Error Handling of type: "MEdiaPlayer error(100,0)
        mp.stop();
        mp.release();
        return false;
    

    public boolean onInfo(MediaPlayer mp, int what, int extra) 
        return false;
    

    /* OTHER STUFF */
    public int getCurrentPosition() 
        if (currentState != State.ERROR) 
            return mPlayer.getCurrentPosition();
         else 
            return 0;
        
    

    public int getDuration() 
        // Prepared, Started, Paused, Stopped, PlaybackCompleted
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.STOPPED, State.PLAYBACK_COMPLETE).contains(currentState)) 
            return mPlayer.getDuration();
         else 
            return 100;
        
    

这是我的 TestFragment(右片段)。注意:左边的 Fragment 是从 TestFragment 调用方法“newChannel(radioChannel)”,每次点击一个列表项。

package net.smart4life.tvplay.fragment;

import java.io.IOException;

import net.smart4life.tvplay.R;
import net.smart4life.tvplay.model.MediaPlayerStateWrapper;
import net.smart4life.tvplay.model.RadioChannel;
import android.app.Fragment;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class TestFragment extends Fragment 

    private RadioChannel radioCh;
    private TextView tv_RadioCh;
    private MediaPlayerStateWrapper mediaWrapper;
    private View view;


    // firstcall
    public TestFragment(RadioChannel radioChannel) 
        this.radioCh = radioChannel;
    

    @Override
    public void onActivityCreated(Bundle savedInstanceState) 
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);

        setRetainInstance(true);

        tv_RadioCh = (TextView) view.findViewById(R.id.radioText);

        mediaWrapper = new MediaPlayerStateWrapper();

        newChannel(radioCh);
    

    public void newChannel (RadioChannel radioChannel) 
        this.radioCh = radioChannel;
        Log.e("RadioChannel", radioCh.getName());
        tv_RadioCh.setText(radioCh.getName());

        if(mediaWrapper.isPlaying()) 
            mediaWrapper.stop();
            mediaWrapper.reset(); 
         else if(mediaWrapper.getState() == MediaPlayerStateWrapper.State.PREPARING) 
            mediaWrapper.release();
            mediaWrapper = new MediaPlayerStateWrapper();
        
        mediaWrapper.setDataSource(radioCh.getUrl().toString());    
        mediaWrapper.prepareAsync();
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) 

        view = inflater.inflate(R.layout.fragment_radio_player, container,
                false);

        return view;
    

    @Override
    public void onDetach() 
        super.onDetach();

        mediaWrapper.release();
    


专业人士,您能帮我解决一个或两个问题吗?

【问题讨论】:

我的修复***.com/a/47992111/4592448 【参考方案1】:

如果一个流无法加载,你经常卡在准备状态,你可以在这里试试,当mediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR

mediaWrapper.reset();
mediaWrapper.release();
System.gc();
mediaWrapper = new MediaPlayerStateWrapper();
mediaWrapper.setDataSource(radioCh.getUrl().toString());
mediaWrapper.prepareAsync();

最好将其放在AsyncTask 中,以避免不响应错误。或者当你得到一个错误时,你必须创建一个新的 MediaPlayer,因为 Media Server 死了

if(mediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR)
    mediaWrapper = new MediaPlayerStateWrapper();
    mediaWrapper.setDataSource(radioCh.getUrl().toString());
    mediaWrapper.prepareAsync();

如果MediaPlayer 正在播放流,您必须先停止并重置它:

mediaWrapper.stop();
mediaWrapper.reset();
mediaWrapper.setDataSource(radioCh.getUrl().toString());
mediaWrapper.prepareAsync();

它对我有用,但我认为这不是最好的方法。当您陷入准备状态时,希望有人能找到更好的解决方案。

【讨论】:

【参考方案2】:

关于audioflinger服务错误,正如您所注意到的,它被标记为“what == 100”或error(100,0)。

根据我的卑微经验,您可以采取哪些措施来避免 audioflinger 错误:

    避免快速调用服务(我确实在创建播放器后添加了大约 500 毫秒的延迟) 限制同时活动的并发 Mediaplayer 的数量。

如何处理audioflinger错误:

    检测audioflinger错误100,设置它发生的标志并禁用GUI(建议只释放播放器,因为当它已经处于错误状态时停止它是不安全的并且会抛出IllegalStateException &错误(38,0) 启动另一个线程来继续测试服务返回(可以通过创建一个新的媒体播放器,没有例外),超时时间为 5-10 秒 当服务返回时,重置标志并重新启用 GUI

所以参考你的代码:

boolean onError(MediaPlayer mp, int what, int extra) 
    // Error Handling of type: "MEdiaPlayer error(100,0)
    mp.release();
    // here you add logic communicating the wrapper or main UI thread
    // to disable GUI and set a flag
    return false;

然后在包装器中添加一个方法来处理这个问题。

如果您解决此问题并发布解决方案,我将不胜感激。我也面临一个非常相似的问题。

【讨论】:

以上是关于Android MediaPlayer AudioStream AudioFlinger 服务器死机!,致命信号 11的主要内容,如果未能解决你的问题,请参考以下文章

Android 音频播放——AudioTrack直接播PCMMediaPlayer播媒体文件可以是audio

android的MediaPlayer.create方法怎么用

如何仅使用 mediaplayer android 通过耳机播放音频

MediaPlayer和AudioTrack播放Audio的区别与联系

怎样在android中实现播放MP4资源文件?代码可行简洁的,不用按钮控制,我就是想做一闪屏

初学Android开发!求一个完整的详细的Android小程序源码参考!