播放器介面

播放器是應用程式的元件,可協助播放媒體項目。Media3 Player 介面會設定播放器通常處理的功能大綱。包括:

  • 影響播放控制項,例如播放、暫停及搜尋
  • 查詢目前播放媒體的屬性,例如播放位置
  • 管理媒體項目的播放清單/佇列
  • 設定播放屬性,例如隨機播放、重複播放、速度和音量
  • 將影片算繪到螢幕上

Media3 也提供 Player 介面的實作,稱為 ExoPlayer。

元件之間的通用介面

Media3 中的多個元件會實作 Player 介面,例如:

元件 說明與行為附註
ExoPlayer 媒體播放器 API,以及 Player 介面的預設實作。
MediaController 與 MediaSession 互動,傳送播放指令。如果 Player 和 MediaSession 位於與 Activity 或 Fragment 不同的 Service 中,而播放器的 UI 位於 Activity 或 Fragment 中,您可以將 MediaController 指派為 UI 元件 (例如 PlayerView 或 Player 可組合項) 的播放器。播放和播放清單方法呼叫會 透過 MediaSession 傳送至 Player。
MediaBrowser 除了 MediaController 提供的功能外,還會與 MediaLibrarySession 互動,瀏覽可用的媒體內容。
SimpleBasePlayer Player 實作方式,可將要實作的方法數量降到最低。使用要連結至 MediaSession 的自訂播放器時,這項功能會很有幫助。
ForwardingSimpleBasePlayer SimpleBasePlayer 子類別,用於將播放作業轉送至另一個 Player,同時允許與 � 相同的行為自訂項目。SimpleBasePlayer使用這個類別可禁止或修改特定播放作業。
RemoteCastPlayer 用來控制遠端 Cast 接收器應用程式播放內容的 Player 實作項目。
CastPlayer Player 實作,可控制本機和遠端 Cast 播放作業。

雖然 MediaSession 不會實作 Player 介面,但建立時需要 Player。目的是要從其他程序或執行緒存取 Player。

Media3 播放架構

如果您可以存取 Player,請直接呼叫其方法來發出播放指令。您可以導入 MediaSession,宣傳播放內容並授予外部來源播放控制權。這些外部來源會實作 MediaController,方便連結至媒體工作階段並發出播放指令要求。

在背景播放媒體時,您需要在以前景服務執行的 MediaSessionService 或 MediaLibraryService 中,存放媒體工作階段和播放器。這樣一來,您就能將播放器與應用程式中含有播放控制項 UI 的 Activity 分開。這時可能需要使用媒體控制器。

這張圖表顯示 Media3 播放元件如何融入媒體應用程式架構。
圖 1:Player 介面在 Media3 架構中扮演重要角色。

播放器狀態

實作 Player 介面的媒體播放器狀態主要包含 4 類資訊:

  1. 播放狀態
  2. 媒體項目播放清單
  3. 播放/暫停屬性,例如:
    • playWhenReady:指出使用者是否希望媒體在可能的情況下播放,或保持暫停狀態
    • 播放遭禁止的原因: 指出播放遭禁止的原因 (如適用),即使 playWhenReady 為 true
    • isPlaying:表示播放器目前是否正在播放內容,只有在播放狀態為 STATE_READY、playWhenReady 為 true 且播放未遭禁止時,才會是 true
  4. 播放位置,包括:

此外,Player 介面可存取可用軌、媒體中繼資料、播放速度、音量,以及播放的其他輔助屬性。

監聽變更

使用 Player.Listener 監聽 Player 中的變更。如要瞭解如何建立及使用監聽器,請參閱 ExoPlayer 說明文件中的「播放器事件」。

請注意,監聽器介面不包含任何回呼,可追蹤正常播放進度。如要持續監控播放進度 (例如設定進度列 UI),您應以適當間隔查詢目前位置。

Kotlin

fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs,
  )

Java

boolean checkPlaybackPosition(long delayMs) {
  return handler.postDelayed(
      () -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
      },
      delayMs);
}

控制播放

Player 介面提供多種方法來操控狀態及控制播放:

自訂 Player 實作

如要建立自訂播放器,可以擴充 Media3 中包含的 SimpleBasePlayer。這個類別提供 Player 介面的基本實作項目,可將您需要實作的方法數量降至最低。

首先,覆寫 getState() 方法。呼叫這個方法時,應填入目前的播放器狀態,包括:

  • 可用的指令集
  • 播放屬性,例如播放狀態為 STATE_READY 時播放器是否應開始播放、目前播放的媒體項目索引,以及目前項目內的播放位置

Kotlin

class CustomPlayer(looper: Looper) : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(Commands.EMPTY) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

private static final class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
        .setAvailableCommands(Commands.EMPTY) // Set which playback commands the player can handle
        // Configure additional playback properties
        .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
        .setCurrentMediaItemIndex(0)
        .setContentPositionMs(0)
        .build();
  }
}

SimpleBasePlayer 會強制使用有效的狀態值組合建立 State。此外,也會處理監聽器,並通知監聽器狀態變更。如要手動觸發狀態更新,請呼叫 invalidateState()。

除了 getState() 方法之外,您只需要實作播放器宣告可用的指令所用的方法。找出與要實作功能相應的可覆寫處理常式方法。舉例來說,覆寫 handleSeek() 方法,即可支援 COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM 和 COMMAND_SEEK_TO_NEXT_MEDIA_ITEM 等作業。

修改 Player 導入方式

您可以選擇不建立完全自訂的 Player,而是使用 ForwardingSimpleBasePlayer 修改現有 Player 的狀態和行為。詳情請參閱自訂頁面指南。