播放器介面

播放器是應用程式中的元件,可協助播放媒體項目。Media3 Player 介面會概述播放器一般處理的功能。包括:

  • 影響播放控制項,例如播放、暫停和跳轉
  • 查詢目前播放媒體的屬性,例如播放位置
  • 管理媒體項目的播放清單/佇列
  • 設定播放屬性,例如隨機播放、重複播放、速度和音量
  • 正在將影片轉譯至螢幕

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

元件之間的共通介面

Media3 中有多個元件實作播放器介面,例如:

元件 說明與行為注意事項
ExoPlayer 媒體播放器 API,以及 Player 介面的預設實作方式。
MediaController MediaSession 互動以傳送播放指令。如果您的 PlayerMediaSession 與玩家 UI 所在的 ActivityFragment 不同,您可以將 MediaController 指派為 PlayerView UI 的玩家。Service播放和播放清單方法的呼叫會透過 MediaSession 傳送至 Player
MediaBrowser 除了 MediaController 提供的功能之外,也可以與 MediaLibrarySession 互動以瀏覽可用的媒體內容。
ForwardingPlayer 將方法呼叫轉送至其他 PlayerPlayer 實作。請使用這個類別,透過覆寫個別方法來隱藏或修改特定作業。
SimpleBasePlayer 可減少實作方法數量的 Player 實作。如果您想將自訂播放器連結至 MediaSession,這就非常實用。
CastPlayer 與 Cast 接收器應用程式通訊的 Player 實作。實際行為取決於基礎的投放工作階段。

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

Media3 播放架構

如果您可以存取 Player,應直接呼叫其方法以發出播放指令。您可以實作 MediaSession 來通告播放,並授予外部來源播放控制項。這些外部來源會實作 MediaController,以便連線至媒體工作階段並發出播放指令要求。

在背景播放媒體時,您需要將媒體工作階段和播放器存放在以前景服務的 MediaSessionServiceMediaLibraryService 中。如此一來,您就可以將播放器與包含播放控制項 UI 的應用程式內活動分開。您可能需要使用媒體控制器。

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

播放器狀態

導入 Player 介面的媒體播放器狀態主要包含以下 4 種資訊:

  1. 播放狀態
  2. 媒體項目的播放清單
  3. 播放/暫停屬性,例如:
    • playWhenReady:表示使用者希望在可行或保持暫停狀態時播放媒體
    • 播放抑制原因:在適用情況下,抑製播放的原因 (即使 playWhenReadytrue 也一樣)
    • isPlaying:指示播放器是否正在播放。只有在播放狀態為 STATE_READYplayWhenReadytrue 且未抑製播放時,這個指標才會為 true
  4. 播放位置,包括:

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

監聽變更

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

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

Kotlin

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

Java

Handler handler = new Handler(Looper.getMainLooper());
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 : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // 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

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

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // 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_ITEMCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM 等作業。