1. 簡介
上次更新時間:2020 年 9 月 9 日
在影片播放中加入 MediaSession 有哪些好處?
媒體工作階段是 Android 平台和媒體應用程式的必要連結。Android 不僅會告知 Android 正在播放媒體,藉此將媒體動作轉送至正確的工作階段,還會告知平台正在播放的內容及控制方式。
透過應用程式顯示 MediaSession 可以帶給使用者各種好處。以下有幾個絕佳的範例
Google 助理
使用者可以透過語音指令 (例如「暫停」),輕鬆與應用程式中的媒體互動。「繼續」和「下一步」媒體的中繼資料也可用於取得目前播放中內容的相關資訊。
Android TV
在大螢幕上,Android TV 應用程式可以在支援 HDMI-CEC 的電視上使用傳統的遙控器。透過播放/暫停、停止、下一個和上一個按鈕發出的指令會轉發至您的應用程式。
畫面上的媒體控制項
從 Android 4.0 (API 級別 14) 開始,系統可以存取媒體工作階段的播放狀態和中繼資料。這項功能可讓螢幕鎖定畫面顯示媒體控制選項和圖片。這個行為會因 Android 版本而異。
背景媒體
即使應用程式正在背景執行,仍可透過上述任何一種情境操控媒體。
環境 運算
將您的媒體與正在播放的內容及其控制方式分享,就能在裝置之間搭起橋樑,讓使用者以多種喜愛的方式與媒體互動。
建構項目
在本程式碼研究室中,您將擴充現有的 Exoplayer 範例,新增媒體工作階段支援功能。您的應用程式將會:
- 正確反映媒體工作階段的運作中狀態
- 將媒體控制項傳遞至 ExoPlayer
- 將佇列中項目的中繼資料傳遞至媒體工作階段
課程內容
- 為何媒體工作階段為使用者提供更豐富的體驗
- 如何建立媒體工作階段及管理其狀態
- 如何將媒體工作階段連結至 ExoPlayer
- 如何在媒體工作階段的播放佇列中加入項目中繼資料
- 如何新增其他 (自訂) 動作
本程式碼研究室著重於 MediaSession SDK。我們不會討論不相關的概念和程式碼區塊 (包括 ExoPlayer 實作的詳細資訊),但會事先提供程式碼區塊,您只要複製及貼上即可。
軟硬體需求
- 最新版 Android Studio (3.5 以上版本)
- 對 Android 應用程式開發的基本知識
2. 開始設定
從哪裡開始?
我們的起點是 ExoPlayer 的主要示範。這項示範包含影片在畫面上播放控制項,但不會立即使用媒體工作階段。不妨從這個地方深入研究並貢獻精彩內容!
取得 ExoPlayer 範例
為了開始跑步,我們先從 ExoPlayer 範例開始。執行下列程式碼,複製 GitHub 存放區。
git clone https://github.com/google/ExoPlayer.git
開啟示範模式
在 Android Studio 中,開啟位於 demos/main
下方的主要示範專案。
Android Studio 會提示您設定 SDK 路徑。如有任何問題,建議您按照「更新 IDE 和 SDK 工具」中的建議項目操作。
如果系統要求您使用最新版 Gradle,請直接進行更新。
請花一點時間瞭解應用程式的設計方式。請注意,目前有兩個活動:SampleChooserActivity 和 PlayerActivity。我們將使用 PlayerActivity 中其餘的程式碼研究室,也就是媒體實際播放的媒體,因此請開啟這個類別並前往下一節。
3. 建立媒體工作階段並管理其狀態
建立媒體工作階段
開啟 PlayerActivity.java
。這個類別會建立 ExoPlayer 及管理其函式,例如將影片算繪到螢幕上。在本活動中,我們會將 ExoPlayer 連線至媒體工作階段。
在類別頂端宣告下列兩個欄位。我們會在這部分內運用這些欄位。
private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;
您將需要新增「extension-mediasession」將專案依附元件附加到「模組:示範」的模組層級 build.gradle
:
implementation project(path: ':extension-mediasession')
請注意,如果將滑鼠遊標懸停在解析 MediaSessionConnector 的錯誤上,Android Studio 就能自動新增這個依附元件:
最後,加入下列指令,解析類別匯入作業:
import android.support.v4.media.session.MediaSessionCompat;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
建立活動時,我們要建立媒體工作階段和媒體工作階段連接器,做為媒體工作階段和 ExoPlayer 之間的中介。
因此,最好一併建立 ExoPlayer。在試用版應用程式中,我們可以將程式碼附加至 initializePlayer()
的結尾。請務必在玩家例項化「之後」加入這個邏輯!
private void initializePlayer() {
if (player == null) {
...
player = ...
...
mediaSession = new MediaSessionCompat(this, "sample");
mediaSessionConnector = new MediaSessionConnector(mediaSession);
mediaSessionConnector.setPlayer(player);
}
...
}
釋出媒體工作階段
不再需要媒體工作階段時,請將其釋出。在 releasePlayer()
中發布 ExoPlayer 時,我們也可以加入以下程式碼:
private void releasePlayer() {
if (mediaSession != null) {
mediaSession.release();
}
...
}
管理媒體工作階段狀態
現在,我們已將媒體工作階段例項化,因此需要確保當使用者與活動互動時,系統已正確反映其狀態。
使用者啟動活動後,媒體工作階段應該會開始運作:
@Override
public void onStart() {
...
if (mediaSession != null) {
mediaSession.setActive(true);
}
}
由於我們的應用程式不會在背景中播放媒體,因此在使用者離開活動時,確保媒體工作階段會自動停用:
@Override
public void onStop() {
super.onStop();
if (mediaSession != null) {
mediaSession.setActive(false);
}
...
}
接著執行示範
- 連接 Android 裝置或啟動模擬器。
- 請務必選取「示範」會獲選從 Android Studio 工具列執行
- 按一下 Android Studio 工具列中的 。
- 應用程式在裝置上啟動後,選取要播放的影片串流。
- 開始播放後,您可以嘗試使用下列
adb
指令控制媒體工作階段:
adb shell media dispatch pause
adb shell media dispatch play
adb shell media dispatch play-pause
adb shell media dispatch fast-forward
adb shell media dispatch rewind
- 同時瞭解 Android 如何檢索您的媒體工作階段。尤其是,只要查看動作欄位,就能確認支援哪些動作。這裡顯示的號碼是一組動作 ID,如 PlaybackState 物件中宣告。如要查看媒體工作階段,請執行:
adb shell dumpsys media_session
- 如果使用附有麥克風的實體裝置,請嘗試叫用 Google 助理並下達語音指令,例如「暫停」。「繼續播放」。「快轉 1 分鐘。」
在 Android TV 上執行的 ExoPlayer 範例。
4. 加入播放佇列中項目的中繼資料
我們現在可以擴充媒體工作階段 (先前在 initializePlayer()
中建立的 MediaSessionConnector) 支援的功能。
新增時間軸佇列導覽工具
ExoPlayer 以時間軸形式呈現媒體的結構。如要進一步瞭解這項機制的運作方式,請花點時間參閱 ExoPlayer 的時間軸物件。利用這種結構,當內容有所變更時,我們就會在問題發生時通知您,並在詢問時顯示目前播放內容的中繼資料。
為達成這個目標,我們會定義 TimelineQueueNavigator。在 initializePlayer()
中找出 MediaSessionConnector 的例項,並在 mediaSession
初始化 之後 加入 TimelineQueueNavigator 的實作方式。
mediaSessionConnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) {
@Override
public MediaDescriptionCompat getMediaDescription(Player player, int windowIndex) {
return new MediaDescriptionCompat.Builder()
.setTitle(player.getCurrentMediaItem().mediaMetadata.title)
.setDescription("MediaDescription description for " + windowIndex)
.setSubtitle("MediaDescription subtitle")
.build();
}
});
新增下列指令,解決類別匯入作業:
import android.support.v4.media.MediaDescriptionCompat;
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator;
您會發現 windowIndex
參數與播放佇列中該索引的項目對應。
在新增部分中繼資料後,現在可以測試 Google 助理能辨識正在播放的內容。在 Android TV 上播放影片時,叫用 Google 助理並詢問「現在播放的是什麼?」
5. 自訂動作
如果您的播放器不支援部分動作,或是您想進一步支援更多動作,現在讓我們深入探討先前在 initializePlayer()
中建立 MediaSessionConnector 的媒體工作階段。
宣告支援的動作
請嘗試使用 mediaSessionConnector.setEnabledPlaybackActions()
自訂要讓媒體工作階段支援的動作。
請注意,完整資料集為:
mediaSessionConnector.setEnabledPlaybackActions(
PlaybackStateCompat.ACTION_PLAY_PAUSE
| PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_SEEK_TO
| PlaybackStateCompat.ACTION_FAST_FORWARD
| PlaybackStateCompat.ACTION_REWIND
| PlaybackStateCompat.ACTION_STOP
| PlaybackStateCompat.ACTION_SET_REPEAT_MODE
| PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
);
我們再看一次該資料如何向平台公開:
- 和先前一樣,開始播放影片。
- 執行以下指令,瞭解 Android 如何查看媒體工作階段的中繼資料:
adb shell dumpsys media_session
- 找出含有中繼資料的那行,然後觀察其名稱和說明是否包含且與
com.google.android.exoplayer2.demo/sample
相關聯。
新增其他動作
我們可以採取額外行動,拓展媒體工作階段的範圍。本節僅提供字幕支援功能。
支援字幕
為媒體工作階段新增字幕支援功能,可讓使用者透過語音切換字幕。將媒體工作階段連接器初始化的位置,加入以下內容:
mediaSessionConnector.setCaptionCallback(new MediaSessionConnector.CaptionCallback() {
@Override
public void onSetCaptioningEnabled(Player player, boolean enabled) {
Log.d("MediaSession", "onSetCaptioningEnabled: enabled=" + enabled);
}
@Override
public boolean hasCaptions(Player player) {
return true;
}
@Override
public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
return false;
}
}
);
最後,請解決所有遺漏的匯入作業。
如要進行測試,請在 Android TV 上叫用 Google 助理,然後說出「啟用字幕」。查看 Logcat 中的訊息,瞭解此呼叫如何傳入您的程式碼。
6. 恭喜
恭喜,您已成功將媒體工作階段新增至範例!
您的功能數量十分龐大,包含:
- 新增媒體工作階段
- 將媒體工作階段連結到 ExoPlayer 的例項
- 新增中繼資料和其他動作
您現已瞭解豐富媒體應用程式所需的重要步驟,可為使用者提供更多元的體驗!
最後 備註
本程式碼研究室是以 ExoPlayer 原始碼的範例為基礎建構而成。您不需要從來源使用 ExoPlayer,建議您改為提取 ExoPlayer 和 MediaSessionConnector 的依附元件,更輕鬆地掌握最新版本。
如要這麼做,只需取代專案的依附元件即可,例如:
implementation project(modulePrefix + 'library-core')
implementation project(path: ':extension-mediasession')
從 Maven 存放區提取,例如:
implementation 'com.google.android.exoplayer:exoplayer-core:2.+'
implementation 'com.google.android.exoplayer:extension-mediasession:2.+'