ExoPlayer 可立即播放大部分自適應直播串流,無須任何特殊設定。詳情請參閱「支援的格式」頁面。
自動調整直播提供定期更新的可用媒體視窗,並定期更新,配合目前的即時動態調整。也就是說,播放位置一律會落在這個時間窗口的某處,在大多數情況下,會接近目前串流產生的即時時間。目前的即時時間與播放位置之間的差異稱為即時偏移。
偵測及監控即時播放
每次更新即時視窗時,已註冊的 Player.Listener
例項都會收到 onTimelineChanged
事件。您可以查詢各種 Player
和 Timeline.Window
方法,擷取目前直播播放的詳細資料,如以下所列和圖示所示。
Player.isCurrentWindowLive
會指出目前播放的媒體項目是否為直播。即使直播已結束,這個值仍會為 true。Player.isCurrentWindowDynamic
會指出目前正在播放的媒體項目是否仍在更新。這通常適用於尚未結束的直播。請注意,在某些情況下,這個標記也適用於非直播。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 Epoch 起算的時間。Window.getCurrentUnixTimeMs
是目前即時自 Unix 紀元以來的時間。伺服器和用戶端之間的已知時鐘差異可能會修正這個值。Window.getDefaultPositionMs
是直播視窗中預設的播放器開始播放位置。
在直播中尋找特定內容
您可以使用 Player.seekTo
在直播視窗中尋找任何內容。傳遞的跳轉位置與直播視窗開始時的相對位置。舉例來說,seekTo(0)
會跳轉至直播視窗的起始位置。玩家會嘗試與跳轉後跳轉的位置維持與跳轉位置相同的即時偏移。
直播視窗也有預設位置,可用於開始播放。這個位置通常靠近即時邊緣。您可以呼叫 Player.seekToDefaultPosition
來尋找預設位置。
即時播放 UI
ExoPlayer 的「預設 UI 元件」會顯示使用中的視窗持續時間,以及其中目前的播放位置。也就是說,每次更新即時視窗時,位置都會向後跳躍。如果您需要不同的行為,例如顯示 Unix 時間或目前的即時偏移,可以分支 PlayerControlView
並視需求進行修改。
設定即時播放參數
ExoPlayer 會使用部分參數,控制播放位置相對於即時邊緣的偏移量,以及可用於調整偏移量的播放速度範圍。
ExoPlayer 會從三個位置取得這些參數的值,並按優先順序遞減排序 (使用找到的第一個值):
- 每個
MediaItem
值都會傳遞至MediaItem.Builder.setLiveConfiguration
。 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,表示估算作業較謹慎,可能需要較長時間才能改善網路條件,而值越低表示預估速度越快,會因為重新緩衝處理的風險較高。
位於 LiveWindowException 和 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 } }