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

时间:2013-03-20 14:14:44

标签: android media-player forceclose servicemanager audioflinger

我有两个片段(左和右),左边的片段中有一个Radiostream列表。通过单击其中一个流,右侧片段应更改流的名称并开始使用给定的uri播放流。

2个问题:

  1. 有些无线电流不是最新的,因此很多无法使用。问题是,这导致我的应用程序强制关闭!我做了错误处理,但在调用这样的流之后我得到了:
  2.   

    03-20 14:23:28.192:A / libc(1021):致命信号11(SIGSEGV)at   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? (见最后的代码)

    1. 我用遥控器控制左侧ListFragment。当我试图从一个频道切换到另一个频道时,一切都非常迟钝。似乎Mediaplayer的重新注册需要很长时间。当我不重新注册时,当我再次调用mediaPlayer.setDataSource(..)时,我得到一个运行时错误。有没有办法在一个MediaPlayer对象上调用.setDataSource两次?
    2. 这是我的代码: 我的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();
          }
      
      }
      

      优点,你能帮我解决一个或两个问题吗?

2 个答案:

答案 0 :(得分:0)

如果流无法加载您经常陷入准备状态,那么您可以在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();

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

答案 1 :(得分:0)

关于audioflinger服务错误,正如您所注意到的那样,它标记为&#34; what == 100&#34;或错误(100,0)。

你可以做些什么来避免我谦虚经历中的音频错误:

  1. 避免快速调用该服务(我在创建播放器后添加了500毫秒的延迟)
  2. 限制同时处于活动状态的媒体播放器数量。
  3. 您可以采取哪些措施来处理audioflinger错误:

    1. 检测audioflinger错误100,设置它发生的标志并禁用GUI (建议仅释放播放器,因为当它已经处于错误状态时停止它是不安全的并且会抛出IllegalStateException&amp; ;错误(38,0)
    2. 启动另一个继续测试服务的线程(可以通过创建一个没有例外的新媒体播放器),暂停时间为5-10秒
    3. 当服务重新启动时,重置标志并重新启用GUI
    4. 所以参考你的代码:

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

      然后添加一个方法来处理包装器。

      当你解决问题并发布解决方案时,我将非常感激。我也面临着一个非常类似的问题。