2013-03-20 109 views
4

我有兩個片段(左和右),並在左邊的片段獲取Radiostreams列表。通過點擊其中一個流,正確的片段應該改變流的名稱並開始播放與給定的URI的流。Android MediaPlayer AudioStream AudioFlinger服務器死亡,致命信號11

2個問題:

  1. 一些廣播流的是不是最新的,所以很多人都沒有工作了。問題是,這導致我的應用程序執行forceclose!我做了錯誤處理,但弄不好流之後,我得到:

03-20 14:23:28.192: A/libc(1021): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=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: reacting to signal 3

03-20 14:23:28.782: I/dalvikvm(1021): Wrote stack traces to '/data/anr/traces.txt'

03-20 14:23:29.192: I/ServiceManager(1021): Waiting for service media.audio_flinger...

我不知道爲什麼。有沒有其他的方式來做錯誤處理?或者有沒有辦法在調用mediaPlayer.setDataSource(uri)之前檢查所有流,以避免準備好uris? (看我的代碼在最後)

  1. 我用遙控器控制左邊的ListFragment。當我試圖從一個頻道切換到另一個頻道時,一切都非常緩慢。看起來Mediaplayer的重組時間很長。當我不重新實現時,當我再次調用mediaPlayer.setDataSource(..)時,我得到一個運行時錯誤。有沒有辦法在一個MediaPlayer對象上調用兩次.setDataSource?

這裏是我的代碼: 我的MediaPlayer的包裝類:

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)」,每次點擊一個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(); 
    } 

} 

優點,請你幫我解決一個或兩個問題嗎?

+0

我的修復https://stackoverflow.com/a/47992111/4592448 – Fortran 2017-12-27 12:26:10

回答

0

如果流無法加載你在準備狀態往往stucked,你可以在這裏試試這個,當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(); 

它爲我工作,但我認爲這不是最好的方法。希望當你處於準備狀態時,有人可以找到一個更好的解決方案來做什麼。

0

關於audioflinger服務錯誤,正如您已經注意到的那樣,它被標記爲「what == 100」或錯誤(100,0)。

,你能做些什麼來避免我卑微的經驗audioflinger錯誤:

  1. 避免快速呼叫服務
  2. 限制的併發數(我創建播放後添加像500米利斯延遲)媒體播放器同時處於活動狀態。

,你能做些什麼來處理audioflinger錯誤:

  1. 檢測的audioflinger錯誤100,將其設置發生了國旗和禁用GUI(僅釋放玩家建議,例如停止它時,它已經處於錯誤狀態是不安全的,將拋出IllegalStateException &錯誤(38,0)
  2. 開始另一個線程,不斷測試服務回來(可以通過創建一個新的mediaplayer沒有例外)與超時的讓我們說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; 
} 

然後添加在包裝上,以處理這個方法。

當您解決問題併發布解決方案時,我將非常感激。我也面臨着一個非常類似的問題。