ExoPlayer 支援大多數自動調整直播,不需特別設定。詳情請參閱「支援的格式」頁面。
自動調整直播會提供可用的媒體視窗,並定期更新,以配合目前的即時時間。也就是說,播放位置一律會在這個視窗中的某個位置,在大多數情況下,會接近串流產生的目前即時時間。目前即時位置與播放位置之間的差異稱為「直播偏移」。
偵測及監控直播重播
每當直播視窗更新時,已註冊的 Player.Listener 執行個體都會收到 onTimelineChanged 事件。您可以查詢各種 Player 和 Timeline.Window 方法,擷取目前直播播放的詳細資料,如下圖所示。

Player.isCurrentWindowLive表示目前播放的媒體項目是否為直播。即使直播已結束,這個值仍為 true。Player.isCurrentWindowDynamic表示目前播放的媒體項目是否仍在更新。這通常適用於尚未結束的直播。請注意,在某些情況下,非直播串流也會設為 true。Player.getCurrentLiveOffset會傳回目前即時時間與播放位置之間的偏移量 (如有)。Player.getDuration會傳回目前直播可播放範圍的長度。Player.getCurrentPosition會傳回相對於直播視窗開頭的播放位置。Player.getCurrentMediaItem會傳回目前的媒體項目,其中MediaItem.liveConfiguration包含應用程式提供的目標直播偏移和直播偏移調整參數覆寫值。Player.getCurrentTimeline會傳回Timeline中的目前媒體結構。您可以使用Player.getCurrentMediaItemIndex和Timeline.getWindow,從Timeline擷取目前的Timeline.Window。在Window中:Window.liveConfiguration包含目標直播偏移和直播偏移調整參數。這些值是根據媒體中的資訊,以及在MediaItem.liveConfiguration中設定的任何應用程式覆寫值。Window.windowStartTimeMs是自 Unix 紀元起算的直播時間範圍開始時間。Window.getCurrentUnixTimeMs是自 Unix 紀元起算的目前即時時間。這個值可能會根據伺服器和用戶端之間的已知時鐘差異進行修正。Window.getDefaultPositionMs是直播視窗中的位置,播放器預設會從該位置開始播放。
在直播中跳轉
你可以使用 Player.seekTo 跳轉至直播視窗中的任何位置。傳遞的跳轉位置是相對於直播可播放範圍的起點。例如,seekTo(0) 會跳轉至直播視窗的開頭。播放器會嘗試在跳轉後,保持與跳轉位置相同的直播偏移量。
直播視窗也有預設位置,播放作業應從該位置開始。這個位置通常接近直播邊緣。您可以呼叫 Player.seekToDefaultPosition,跳轉至預設位置。
直播播放 UI
ExoPlayer 的預設 UI 元件會顯示直播視窗的時間長度,以及目前的播放位置。這表示每次更新直播視窗時,位置都會向後跳。如需不同行為,例如顯示 Unix 紀元時間或目前的直播偏移,可以分支 PlayerControlView 並視需求修改。
設定直播播放參數
ExoPlayer 會使用一些參數,控制播放位置與直播邊緣的偏移量,以及可用於調整這個偏移量的播放速度範圍。
ExoPlayer 會從三個位置取得這些參數的值,優先順序由高到低 (使用找到的第一個值):
- 傳遞至
MediaItem.Builder.setLiveConfiguration的每個MediaItem值。 - 全域預設值設定於
DefaultMediaSourceFactory。 - 直接從媒體讀取的值。
Kotlin
// Global settings. val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build() // Per MediaItem settings. val mediaItem = MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build() ) .build() player.setMediaItem(mediaItem)
Java
// Global settings. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build(); // Per MediaItem settings. MediaItem mediaItem = new MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()) .build(); player.setMediaItem(mediaItem);
可用的設定值如下:
targetOffsetMs:目標直播偏移。播放器會盡可能在播放期間,嘗試接近這個直播偏移值。minOffsetMs:允許的直播偏移量下限。即使根據目前的網路狀況調整偏移量,播放器在播放期間也不會嘗試低於這個偏移量。maxOffsetMs:允許的直播偏移量上限。即使根據目前的網路狀況調整偏移量,播放器也不會在播放期間嘗試超過這個偏移量。minPlaybackSpeed:播放器在嘗試達到目標直播偏移時,可使用的最低播放速度。maxPlaybackSpeed:播放器在嘗試達到目標直播偏移量時,可使用的最快播放速度。
調整播放速度
播放低延遲直播時,ExoPlayer 會稍微調整播放速度,藉此調整直播偏移量。播放器會嘗試比對媒體或應用程式提供的目標直播偏移,但也會嘗試因應網路狀況變化。舉例來說,如果播放期間發生重新緩衝處理,播放器會稍微降低播放速度,進一步遠離直播邊緣。如果網路隨後變得足夠穩定,可再次支援更接近直播邊緣的播放,播放器會加快播放速度,回到目標直播偏移。
如果不需要自動調整播放速度,可以將 minPlaybackSpeed 和 maxPlaybackSpeed 屬性設為 1.0f,停用這項功能。同樣地,只要將這些值明確設為 1.0f 以外的值,即可為非低延遲直播啟用這項功能。如要進一步瞭解如何設定這些屬性,請參閱設定一節。
自訂播放速度調整演算法
如果啟用速度調整功能,LivePlaybackSpeedControl 會定義要進行哪些調整。您可以實作自訂 LivePlaybackSpeedControl,或自訂預設實作 DefaultLivePlaybackSpeedControl。在這兩種情況下,都可以在建構播放器時設定例項:
Kotlin
val player = ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build() ) .build()
Java
ExoPlayer player = new ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( new DefaultLivePlaybackSpeedControl.Builder() .setFallbackMaxPlaybackSpeed(1.04f) .build()) .build();
DefaultLivePlaybackSpeedControl 的相關自訂參數如下:
fallbackMinPlaybackSpeed和fallbackMaxPlaybackSpeed:如果媒體和應用程式提供的MediaItem都未定義限制,則可用於調整的播放速度下限和上限。proportionalControlFactor:控制速度調整的平滑程度。值越高,調整越突然且反應越快,但也越容易聽得出來。值越小,速度之間的轉換越流暢,但速度會較慢。targetLiveOffsetIncrementOnRebufferMs:每當發生重新緩衝時,這個值就會加到目標直播偏移量,以便更謹慎地進行。如要停用這項功能,請將值設為 0。minPossibleLiveOffsetSmoothingFactor:指數平滑係數,用於根據目前緩衝的媒體,追蹤可能的最小直播偏移量。如果值非常接近 1,表示預估值較為謹慎,可能需要較長時間才能根據改善的網路狀況進行調整;如果值較低,表示預估值會更快調整,但發生重新緩衝處理的風險較高。
BehindLiveWindowException 和 ERROR_CODE_BEHIND_LIVE_WINDOW
如果播放器暫停或緩衝處理的時間過長,播放位置可能會落後直播可播放範圍。如果發生這種情況,播放就會失敗,系統會使用 Player.Listener.onPlayerError 回報錯誤代碼為 ERROR_CODE_BEHIND_LIVE_WINDOW 的例外狀況。建議您在預設位置繼續播放,以處理這類錯誤。試用版應用程式的 PlayerActivity 示範了這個方法。
Kotlin
override fun onPlayerError(error: PlaybackException) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition() player.prepare() } else { // Handle other errors } }
Java
@Override public void onPlayerError(PlaybackException error) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition(); player.prepare(); } else { // Handle other errors } }