2016-02-29 42 views
1

下面的代碼是託管的MediaPlayer從URL播放MP3流的活動的最小例子之前。按「btn1」觸發URL1播放(NPR播客)。按「btn2」觸發URL2播放(不同電臺的mp3錄音)。的Android MediaPlayer的 - 用100 onBufferingUpdate稱爲調用0

public class MainActivity extends AppCompatActivity { 

    public static final String TAG = MainActivity.class.getSimpleName(); 
    static final String URL1 = "http://13503.mc.tritondigital.com/WAITWAIT_PODCAST/media-session/822d578a-af47-4d7e-b3ca-d18af78071bc/anon.npr-podcasts/podcast/344098539/464996449/npr_464996449.mp3"; 
    static final String URL2 = "http://www.selbie.com/wrekapp/Fri0130.mp3"; 

    MediaPlayer _player; 

    void startPlayerAsync(String url) { 

     stopPlayer(); // _player.reset(); _player.release(); _player=null; 

     Log.d(TAG, "==================="); 
     Log.d(TAG, "Starting new player for URL: "+url); 

     _player = new MediaPlayer(); 

     try 
     { 
      _player.setDataSource(url); 
     } 
     catch (IOException e) { 
      Log.d(TAG, "IOException", e); 
      return; 
     } 

     _player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() { 
      @Override 
      public void onBufferingUpdate(MediaPlayer mp, int percent) { 
       Log.d(TAG, "onBufferingUpdate: " + percent); 
      } 
     }); 

     _player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 
      @Override 
      public void onPrepared(MediaPlayer mp) { 
       if (mp == _player) 
       { 
        Log.d(TAG, "onPrepared"); 
        _player.start(); 
       } 
      } 
     }); 

     _player.prepareAsync(); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       startPlayerAsync(URL1); 
      } 
     }); 

     findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       startPlayerAsync(URL2); 
      } 
     }); 
    } 

} 

當點擊BTN1,之前聽到音頻logspew的總結如下:

02-28 19:47:43.764 D/MainActivity: =================== 
02-28 19:47:43.764 D/MainActivity: Starting new player for URL: http://13503.mc.tritondigital.com/WAITWAIT_PODCAST/media-session/822d578a-af47-4d7e-b3ca-d18af78071bc/anon.npr-podcasts/podcast/344098539/464996449/npr_464996449.mp3 
02-28 19:47:44.695 1D/MainActivity: OnBufferingUpdate: 0 
02-28 19:47:44.697 D/MediaPlayer: setSubtitleAnchor in MediaPlayer 
02-28 19:47:44.699 D/MainActivity: onPrepared 
02-28 19:47:44.703 D/MainActivity: onBufferingUpdate: 0 
02-28 19:47:45.703 D/MainActivity: onBufferingUpdate: 6 
02-28 19:47:46.704 D/MainActivity: onBufferingUpdate: 9 
... 

當按下爲其他URL BTN2,有一個稍微不同的行爲:

02-28 19:47:18.892 D/MainActivity: =================== 
02-28 19:47:18.893 D/MainActivity: Starting new player for URL: http://www.selbie.com/wrekapp/Fri0130.mp3 
02-28 19:47:20.453 D/MainActivity: onBufferingUpdate: 100  <==== NOTICE THIS 
02-28 19:47:20.453 D/MediaPlayer: setSubtitleAnchor in MediaPlayer 
02-28 19:47:20.465 D/MainActivity: onPrepared 
02-28 19:47:20.676 D/MainActivity: onBufferingUpdate: 0 
02-28 19:47:21.680 D/MainActivity: onBufferingUpdate: 2 
... 

在第一情況下,存在之前onPrepared早期onBufferingUpdate(0)事件燒製。然後onBufferingUpdate呼叫的週期性間隔遞增從0到100作爲流播放。

但是在第二種情況下,存在虛假onBufferingUpdate(100)觸發的事件。但幾秒鐘後,它與onPreparedonBufferingUpdate(0)糾正。

不要緊,用戶點擊第一或流哪個按鈕被啓動。我甚至將URL2的mp3文件從其原始服務器移到另一個。關於第二個URL的mp3流會引起MediaPlayer想要以這種方式行事。在我的實際應用程序中,這會導致我的進度控制的「二級進度」行在顯示預期緩衝之前顯示一秒的實線。這是應用程序的視覺缺陷。

我的解決方法是忽略所有onBufferingUpdate事件,直到onPrepared被觸發爲止。在我做出改變之前,我想了解一下爲什麼會發生這種情況。並且確保它安全地假設在流開始之前緩衝達到100%是不可能的。這是正確的修復嗎?

+0

好像有與這裏提到的媒體播放器回調問題(https://code.google.com/p/android/issues/detail?id=65564) 。您發佈解決方案和解決方法很好。 –

回答

0

鑑於沒有其他選擇,我決定簡單地忽略任何呼叫與100的值onBufferingUpdate在MediaPlayer在準備狀態和之前沒有被調用與非零值:

實際上,代碼變成這樣:

_player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() { 
     @Override 
     public void onBufferingUpdate(MediaPlayer mp, int percent) { 

      // percent can be something awkward like "-2147483648" on a live source. Just clamp it. 
      if (percent < 0) { 
       percent = 0; 
      } 
      else if (percent > 100) { 
       percent = 100; 
      } 

      if ((_state == Preparing) && (_secondaryPercent == 0) && (percent == 100)) { 
        Log.d(TAG, "onBufferingUpdate(100) invoked while in preparing state - ignoring"); 
      } 
      else if (_secondaryPercent != percent) { 
       _secondaryPercent = percent; 
       handleBufferingUpdate(percent); 
      } 
     } 
    });