Android MediaPlayer AudioStream AudioFlinger скончался !, Фатальный сигнал 11

У меня есть два фрагмента (слева и справа) и попадание в левый фрагмент списка радиоисточников. Нажав на один из этих потоков, правый фрагмент должен изменить имя потока и начать воспроизведение потока с заданным uri.

2 Проблемы:

  1. Некоторые из радиопотоков не обновлены, поэтому многие из них больше не работают. Проблема в том, что это приводит к тому, что мое приложение делает силовое закрытие! Я сделал обработку ошибок, но после вызова такого потока я получаю:

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? (См. Мой код в конце)

  1. Я управляю левой ListFragment с помощью пульта дистанционного управления. Когда я пытаюсь переключиться очень быстро с одного канала на другой, все очень лаги. Похоже, что восстановление медиапланера происходит очень долго. Когда я не переучиваюсь, я получаю runtimeerror, когда снова вызываю mediaPlayer.setDataSource (..). Есть ли способ вызвать .setDataSource два раза на одном объекте MediaPlayer?

Вот мой код: My 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; } } } 

Вот мой тестовый фрагмент (правый фрагмент). Примечание: левый фрагмент вызывает метод «newChannel (radioChannel)» из TestFragment, каждый раз, когда был нажат элемент listitem.

 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, потому что 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(); 

    Он работает для меня, но я думаю, что это не лучший способ. Надеюсь, кто-то может найти лучшее решение, что делать, когда вы застряли в состоянии подготовки.

    Что касается ошибки службы звуковой системы, как вы заметили, она отмечена «what == 100» или ошибкой (100,0).

    Что вы можете сделать, чтобы избежать ошибки audioflinger из моего скромного опыта:

    1. Избегайте быстрых вызовов службы (я добавляю задержка 500 миллисекунд после создания проигрывателя)
    2. Одновременно ограничивайте количество одновременных медиапланеров.

    Что вы можете сделать для обработки ошибки аудиофрагментатора:

    1. Обнаружить ошибку аудиофрагментатора 100, установить флаг, в котором он произошел, и отключить графический интерфейс (рекомендуется только освободить плеер, так как остановка его, когда она уже находится в состоянии ошибки, небезопасна и будет вызывать IllegalStateException & error (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; } 

    Затем вы добавляете метод для обработки этого в обертке.

    Я был бы очень благодарен, когда вы это выработаете и опубликуете решение. Я тоже сталкиваюсь с очень похожей проблемой.