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



我有两个片段(左和右),并获得在左片段的Radiostreams列表。通过点击其中一个流,右边的片段应该改变流的名称,并开始播放带有给定uri的流。

2的问题:

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

03-20 14:23:28.192: A/libc(1021): Fatal signal 11 (SIGSEGV) at0 x00000000(代码= 1)

03-20 14:23:28.192: W/AudioSystem(1021): AudioFlinger server died!

03-20 14:23:28.192: W/IMediaDeathNotifier(1021): media server died

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

03-20 14:23:28.192: I/ServiceManager(1021): Waiting for service .日志示例media.audio_flinger…

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

03-20 14:23:28.782: I/dalvikvm(1021):写堆栈跟踪到"/数据/一定/traces.txt"

03-20 14:23:29.192: I/ServiceManager(1021): Waiting for service .日志示例media.audio_flinger…

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

  1. 我用遥控器控制左边的ListFragment。当我试着快速地从一个频道切换到另一个频道时,一切都很慢。看来重新启用Mediaplayer要花很长时间。当我不加强时,当我再次调用mediaPlayer.setDataSource(..)时,我会得到一个运行时错误。是否有一种方法来调用。setdatasource两次对一个MediaPlayer对象?
下面是我的代码:我的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)。注意:左边的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();
    }
}
专业人士,你能帮我回答一个或两个问题吗?

如果一个流不能加载,你经常被困在准备状态,你可以试试这里,当mediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR:

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

最好放在AsyncTask中,以避免不响应错误。或者当你得到一个错误,你必须创建一个新的MediaPlayer,因为媒体服务器死亡:

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

这对我有用,但我认为这不是最好的方法。当你被困在准备状态时,希望有人能找到一个更好的解决方案。

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

你可以做些什么来避免audioflinger错误从我的拙见:

  1. 避免对服务的快速调用(我在创建播放器后添加了500毫秒的延迟)
  2. 限制同时活动的媒体播放器数量。

如何处理audioflinger错误:

  1. 检测audioflinger错误100,设置它发生的标志并禁用GUI(建议只释放播放器,因为当它已经处于错误状态时停止它是不安全的,并且会抛出IllegalStateException &38岁的错误(0)
  2. 启动另一个线程,保持测试服务返回(可以通过创建一个没有异常的新媒体播放器),超时时间为5-10秒
  3. 当服务返回时,重置标志并重新启用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;
}

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

如果你能解决这个问题并发布解决方案,我将非常感激。我也面临着类似的问题。

最新更新