W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
AVSession 框架有四個主要的類,控制著整個框架的核心,下圖簡單的說明四個核心媒體框架控制類的關(guān)系。
媒體瀏覽器,通常在客戶端創(chuàng)建,成功連接媒體服務后,通過媒體控制器 AVBrowse r向服務端發(fā)送播放控制指令。
其主要流程為,調(diào)用 connect 方法向 AVBrowserService 發(fā)起連接請求,連接成功后在回調(diào)方法 AVConnectionCallback.onConnected 中發(fā)起訂閱數(shù)據(jù)請求,并在回調(diào)方法 AVSubscriptionCallback.onAVElementListLoaded 中保存請求的媒體播放數(shù)據(jù)。
媒體控制器,在客戶端 AVBrowser 連接服務成功后的回調(diào)方法 AVConnectionCallback.onConnected 中創(chuàng)建,用于向 Service 發(fā)送播放控制指令,并通過實現(xiàn) AVControllerCallback 回調(diào)來響應服務端媒體狀態(tài)變化,例如曲目信息變更、播放狀態(tài)變更等,從而完成UI刷新。
Service
媒體瀏覽器服務,通常在服務端,通過媒體會話 AVSession 與媒體瀏覽器建立連接,并通過實現(xiàn) Player 進行媒體播放。其中有兩個重要的方法:
媒體會話,通常在 AVBrowserService 的 onStart 中創(chuàng)建,通過 setAVToken 方法設置到 AVBrowserService 中,并通過實現(xiàn) AVSessionCallback 回調(diào)來接收和處理媒體控制器 AVController 發(fā)送的播放控制指令,如播放、暫停、跳轉(zhuǎn)至上一曲、跳轉(zhuǎn)至下一曲等。
除了上述四個類,AVSession 框架還有 AVElement。
媒體元素,用于將播放列表從 AVBrowserService 傳遞給 AVBrowser。
接口名 | 描述 |
---|---|
AVBrowser(Context context, ElementName name, AVConnectionCallback callback, PacMap options) | 構(gòu)造 AVBrowser 實例,用于瀏覽 AVBrowserService 提供的媒體數(shù)據(jù)。 |
void connect() | 連接 AVBrowserService。 |
void disconnect() | 與 AVBrowserService 斷開連接。 |
boolean isConnected() | 判斷當前是否已經(jīng)與 AVBrowserService 連接。 |
ElementName getElementName() | 獲取 AVBrowserService 的ohos.bundle.ElementName實例。 |
String getRootMediaId() | 獲取默認媒體 id。 |
PacMap getOptions() | 獲取 AVBrowserService 提供的附加數(shù)據(jù)。 |
AVToken getAVToken() | 獲取媒體會話的令牌。 |
void getAVElement(String mediaId, AVElementCallback callback) | 輸入媒體的 id,查詢對應的 ohos.media.common.sessioncore.AVElement 信息,查詢結(jié)果會通過 callback 返回。 |
void subscribeByParentMediaId(String parentMediaId, AVSubscriptionCallback callback) | 查詢指定媒體 id 包含的所有媒體元素信息,并訂閱它的媒體信息更新通知。 |
void subscribeByParentMediaId(String parentMediaId, PacMap options, AVSubscriptionCallback callback) | 基于特定于服務的參數(shù)來查詢指定媒體 id 中的媒體元素的信息,并訂閱它的媒體信息更新通知。 |
void unsubscribeByParentMediaId(String parentMediaId) | 取消訂閱對應媒體 id 的信息更新通知。 |
void unsubscribeByParentMediaId(String parentMediaId, AVSubscriptionCallback callback) | 取消訂閱與指定 callback 相關(guān)的媒體 id 的信息更新通知。 |
接口名 | 描述 |
---|---|
abstract AVBrowserRoot onGetRoot(String callerPackageName, int clientUid, PacMap options) | 回調(diào)方法,用于返回應用程序的媒體內(nèi)容的根信息,在 AVBrowser.connect()后進行回調(diào)。 |
abstract void onLoadAVElementList(String parentMediaId, AVBrowserResult result) | 回調(diào)方法,用于返回應用程序的媒體內(nèi)容的結(jié)果信息 AVBrowserResult,其中包含了子節(jié)點的 AVElement 列表,在 AVBrowser 的方法 subscribeByParentMediaId 或 notifyAVElementListUpdated 執(zhí)行后進行回調(diào)。 |
abstract void onLoadAVElement(String mediaId, AVBrowserResult result) | 回調(diào)方法,用于獲取特定的媒體項目 AVElement 結(jié)果信息,在 AVBrowser.getAVElement 方法執(zhí)行后進行回調(diào)。 |
AVToken getAVToken() | 獲取 AVBrowser 與 AVBrowserService 之間的會話令牌。 |
void setAVToken(AVToken token) | 設置 AVBrowser 與 AVBrowserService 之間的會話令牌。 |
final PacMap getBrowserOptions() | 獲取 AVBrowser 在連接 AVBrowserService 時設置的服務參數(shù)選項。 |
final AVRemoteUserInfo getCallerUserInfo() | 獲取當前發(fā)送請求的調(diào)用者信息。 |
void notifyAVElementListUpdated(String parentMediaId) | 通知所有已連接的 AVBrowser 當前父節(jié)點的子節(jié)點已經(jīng)發(fā)生改變。 |
void notifyAVElementListUpdated(String parentId, PacMap options) | 通知所有已連接的 AVBrowser 當前父節(jié)點的子節(jié)點已經(jīng)發(fā)生改變,可設置服務參數(shù)。 |
接口名 | 描述 |
---|---|
AVController(Context context, AVToken avToken) | 構(gòu)造 AVController 實例,用于應用程序與 AVSession 進行交互以控制媒體播放。 |
static boolean setControllerForAbility(Ability ability, AVController controller) | 將媒體控制器注冊到 ability 以接收按鍵事件。 |
boolean setAVControllerCallback(AVControllerCallback callback) | 注冊一個回調(diào)以接收來自 AVSession 的變更,例如元數(shù)據(jù)和播放狀態(tài)變更。 |
boolean releaseAVControllerCallback(AVControllerCallback callback) | 釋放與 AVSession 之間的回調(diào)實例。 |
List<AVQueueElement> getAVQueueElement() | 獲取播放隊列。 |
CharSequence getAVQueueTitle() | 獲取播放隊列的標題。 |
AVPlaybackState getAVPlaybackState() | 獲取播放狀態(tài)。 |
boolean dispatchAVKeyEvent(KeyEvent keyEvent) | 應用分發(fā)媒體按鍵事件給會話以控制播放。 |
void sendCustomCommand(String command, PacMap pacMap, GeneralReceiver receiverCb) | 應用向 AVSession 發(fā)送自定義命令,參考ohos.media.common.sessioncore.AVSessionCallback.onCommand。 |
IntentAgent getAVSessionAbility() | 獲取啟動用戶界面的IntentAgent。 |
AVToken getAVToken() | 獲取應用連接到會話的令牌。此令牌用于創(chuàng)建媒體播放控制器。 |
void adjustAVPlaybackVolume(int direction, int flags) | 調(diào)節(jié)播放音量。 |
void setAVPlaybackVolume(int value, int flags) | 設置播放音量,要求支持絕對音量控制。 |
PacMap getOptions() | 獲取與此控制器連接的AVSession的附加數(shù)據(jù)。 |
long getFlags() | 獲取 AVSession 的附加標識,標記在 AVSession 中的定義。 |
AVMetadata getAVMetadata() | 獲取媒體資源的元數(shù)據(jù)ohos.media.common.AVMetadata。 |
AVPlaybackInfo getAVPlaybackInfo() | 獲取播放信息。 |
String getSessionOwnerPackageName() | 獲得 AVSession 實例的應用程序的包名稱。 |
PacMap getAVSessionInfo() | 獲取會話的附加數(shù)據(jù)。 |
PlayControls getPlayControls() | 獲取一個 PlayControls 實例,將用于控制播放,比如控制媒體播放、停止、下一首等。 |
接口名 | 描述 |
---|---|
AVSession(Context context, String tag) | 構(gòu)造 AVSession 實例,用于控制媒體播放。 |
AVSession(Context context, String tag, PacMap sessionInfo) | 構(gòu)造帶有附加會話信息的 AVSession 實例,用于控制媒體播放。 |
void setAVSessionCallback(AVSessionCallback callback) | 設置回調(diào)函數(shù)來控制播放器,控制邏輯由應用實現(xiàn)。如果 callback 為 null 則取消控制。 |
boolean setAVSessionAbility(IntentAgent ia) | 給 AVSession 設置一個IntentAgent,用來啟動用戶界面。 |
boolean setAVButtonReceiver(IntentAgent ia) | 為媒體按鍵接收器設置一個 IntentAgent,以便應用結(jié)束后,可以通過媒體按鍵重新拉起應用。 |
void enableAVSessionActive(boolean active) | 設置是否激活媒體會話。當會話準備接收命令時,將輸入?yún)?shù)設置為 true。如果會話停止接收命令,則設置為 false。 |
boolean isAVSessionActive() | 查詢會話是否激活。 |
void sendAVSessionEvent(String event, PacMap options) | 向所有訂閱此會話的控制器發(fā)送事件。 |
void release() | 釋放資源,應用播放完之后需調(diào)用。 |
AVToken getAVToken() | 獲取應用連接到會話的令牌。此令牌用于創(chuàng)建媒體播放控制器。 |
AVController getAVController() | 獲取會話構(gòu)造時創(chuàng)建的控制器,方便應用使用。 |
void setAVPlaybackState(AVPlaybackState state) | 設置當前播放狀態(tài)。 |
void setAVMetadata(AVMetadata avMetadata) | 設置媒體資源元數(shù)據(jù)ohos.media.common.AVMetadata。 |
void setAVQueue(List<AVQueueElement> queue) | 設置播放隊列。 |
void setAVQueueTitle(CharSequence queueTitle) | 設置播放隊列的標題,UI會顯示此標題。 |
void setOptions(PacMap options) | 設置此會話關(guān)聯(lián)的附加數(shù)據(jù)。 |
AVCallerUserInfo getCurrentControllerInfo() | 獲取發(fā)送當前請求的媒體控制器信息。 |
接口名 | 描述 |
---|---|
AVElement(AVDescription description, int flags) | 構(gòu)造 AVElement 實例。 |
int getFlags() | 獲取flags的值。 |
boolean isScannable() | 判斷媒體是否可掃描,如:媒體有子節(jié)點,則可繼續(xù)掃描獲取子節(jié)點內(nèi)容。 |
boolean isPlayable() | 檢查媒體是否可播放。 |
AVDescription getAVDescription() | 獲取媒體的詳細信息。 |
String getMediaId() | 獲取媒體的id。 |
使用 AVSession 媒體框架創(chuàng)建一個播放器示例,分為創(chuàng)建客戶端和創(chuàng)建服務端。
創(chuàng)建客戶端
在客戶端 AVClientAbility 中聲明 AVBrowser 和 AVController,并向服務端發(fā)送連接請求。
public class AVClientAbility extends Ability {
// 媒體瀏覽器
private AVBrowser avBrowser;
// 媒體控制器
private AVController avController;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// 用于指向媒體瀏覽器服務的包路徑和類名
ElementName elementName = new ElementName("", "com.huawei.samples.audioplayer", "com.huawei.samples.audioplayer.AVService");
// connectionCallback 在調(diào)用 avBrowser.connect 方法后進行回調(diào)。
avBrowser = new AVBrowser(context, elementName, connectionCallback, null);
// avBrowser 發(fā)送對媒體瀏覽器服務的連接請求。
avBrowser.connect();
// 將媒體控制器注冊到 ability 以接收按鍵事件。
AVController.setControllerForAbility(this, avController);
}
}
AVConnectionCallback 回調(diào)接口中的方法為可選實現(xiàn),通常需要會在 onConnected 中訂閱媒體數(shù)據(jù)和創(chuàng)建媒體控制器 AVController。
// 發(fā)起連接(avBrowser.connect)后的回調(diào)方法實現(xiàn)
private AVConnectionCallback connectionCallback = new AVConnectionCallback() {
@Override
public void onConnected() {
// 成功連接媒體瀏覽器服務時回調(diào)該方法,否則回調(diào) onConnectionFailed()。
// 重復訂閱會報錯,所以先解除訂閱。
avBrowser.unsubscribeByParentMediaId(avBrowser.getRootMediaId());
// 第二個參數(shù) AVSubscriptionCallback,用于處理訂閱信息的回調(diào)。
avBrowser.subscribeByParentMediaId(AV_ROOTavBrowser.getRootMediaId(), avSubscriptionCallback);
AVToken token = avBrowser.getAVToken();
avController = new AVController(AVClient.this, token); // AVController第一個參數(shù)為當前類的context
// 參數(shù) AVControllerCallback,用于處理服務端播放狀態(tài)及信息變化時回調(diào)。
avController.setAVControllerCallback(avControllerCallback);
// ...
}
// 其它回調(diào)方法(可選)
// ...
};
通常在訂閱成功時,在 AVSubscriptionCallback 回調(diào)接口 onAVElementListLoaded 中保存服務端回傳的媒體列表。
// 發(fā)起訂閱信息(avBrowser.subscribeByParentMediaId)后的回調(diào)方法實現(xiàn)
private AVSubscriptionCallback avSubscriptionCallback = new AVSubscriptionCallback() {
@Override
public void onAVElementListLoaded(String parentId, List<AVElement> children) {
// 訂閱成功時回調(diào)該方法,parentID 為標識,children 為服務端回傳的媒體列表
super.onAVElementListLoaded(parentId, children);
list.addAll(children);
// ...
}
};
AVControllerCallback 回調(diào)接口中的方法均為可選方法,主要用于服務端播放狀態(tài)及信息的變化后對客戶端的回調(diào),客戶端可在這些方法中實現(xiàn)UI的刷新。
// 服務對客戶端的媒體數(shù)據(jù)或播放狀態(tài)變更后的回調(diào)
private AVControllerCallback avControllerCallback = new AVControllerCallback() {
@Override
public void onAVMetadataChanged(AVMetadata metadata) {
// 當服務端調(diào)用 avSession.setAVMetadata(avMetadata)時,此方法會被回調(diào)。
super.onAVMetadataChanged(metadata);
AVDescription description = metadata.getAVDescription();
String title = description.getTitle().toString();
PixelMap pixelMap = description.getIcon();
// ...
}
@Override
public void onAVPlaybackStateChanged(AVPlaybackState playbackState) {
// 當服務端調(diào)用avSession.setAVPlaybackState(...)時,此方法會被回調(diào)。
super.onAVPlaybackStateChanged(playbackState);
long position = playbackState.getCurrentPosition();
// ...
}
// 其它回調(diào)方法(可選)
// ...
};
完成以上實現(xiàn)后,則應用可以在UI事件中調(diào)用avController的方法向服務端發(fā)送播放控制指令。
// 在 UI 播放與暫停按鈕的點擊事件中向服務端發(fā)送播放或暫停指令
public void toPlayOrPause() {
switch (avController.getAVPlaybackState().getAVPlaybackState()) {
case AVPlaybackState.PLAYBACK_STATE_NONE: {
avController.getPlayControls().prepareToPlay();
avController.getPlayControls().play();
break;
}
case AVPlaybackState.PLAYBACK_STATE_PLAYING: {
avController.getPlayControls().pause();
break;
}
case AVPlaybackState.PLAYBACK_STATE_PAUSED: {
avController.getPlayControls().play();
break;
}
default: {
// ...
}
}
}
其它播放控制根據(jù)業(yè)務是否需要實現(xiàn),比如:
avController.getPlayControls().playNext();
avController.getPlayControls().playPrevious();
avController.getPlayControls().playFastForward();
avController.getPlayControls().rewind();
avController.getPlayControls().seekTo(1000);
avController.getPlayControls().stop();
// ...
也可以主動獲取媒體信息、播放狀態(tài)等數(shù)據(jù):
AVMetadata avMetadata = avController.getAVMetadata();
AVPlaybackState avPlaybackState = avController.getAVPlaybackState();
// ...
創(chuàng)建服務端
在服務端 AVService 中聲明 AVSession 和 Player。
public class AVService extends AVBrowserService {
// 媒體會話
private AVSession avSession;
// 媒體播放器
private Player player;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
avSession = new AVSession(this, "AVService");
setAVToken(avSession.getAVToken());
// 設置 sessioncallback,用于響應客戶端的媒體控制器發(fā)起的播放控制指令。
avSession.setAVSessionCallback(avSessionCallback);
// 設置播放狀態(tài)初始狀態(tài)為 AVPlaybackState.PLAYBACK_STATE_NONE。
AVPlaybackState playbackState = new AVPlaybackState.Builder().setAVPlaybackState(AVPlaybackState.PLAYBACK_STATE_NONE, 0, 1.0f).build();
avSession.setAVPlaybackState(playbackState);
// 完成播放器的初始化,如果使用多個 Player,也可以在執(zhí)行播放時初始化。
player = new Player(this);
}
@Override
public AVBrowserRoot onGetRoot(String clientPackageName, int clientUid, PacMap rootHints) {
// 響應客戶端 avBrowser.connect()方法。若同意連接,則返回有效的AVBrowserRoot實例,否則返回null
return new AVBrowserRoot(AV_ROOT, null);
}
@Override
public void onLoadAVElementList(String parentId, AVBrowserResult result) {
LogUtil.info(TAG, "onLoadChildren");
// 響應客戶端avBrowser.subscribeByParentMediaId(...)方法。
// 先執(zhí)行該方法detachForRetrieveAsync()
result.detachForRetrieveAsync();
// externalAudioItems緩存媒體文件,請開發(fā)者自行實現(xiàn)。
result.sendAVElementList(externalAudioItems.getAudioItems());
}
@Override
public void onLoadAVElementList(String s, AVBrowserResult avBrowserResult, PacMap pacMap) {
// 響應客戶端avBrowser.subscribeByParentMediaId(String, PacMap, AVSubscriptionCallback)方法。
}
@Override
public void onLoadAVElement(String s, AVBrowserResult avBrowserResult) {
// 響應客戶端avBrowser.getAVElement(String, AVElementCallback)方法。
}
}
響應客戶端的媒體控制器發(fā)起的播放控制指令的回調(diào)實現(xiàn)。
private AVSessionCallback avSessionCallback = new AVSessionCallback() {
@Override
public void onPlay() {
super.onPlay();
// 當客戶端調(diào)用avController.getPlayControls().play()時,該方法會被回調(diào)。
// 響應播放請求,開始播放。
if (avSession.getAVController().getAVPlaybackState().getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PAUSED) {
if (player.play()) {
AVPlaybackState playbackState = new AVPlaybackState.Builder().setAVPlaybackState(
AVPlaybackState.PLAYBACK_STATE_PLAYING, player.getCurrentTime(),
player.getPlaybackSpeed()).build();
avSession.setAVPlaybackState(playbackState);
}
}
}
@Override
public void onPause() {
super.onPause();
// 當客戶端調(diào)用avController.getPlayControls().pause()時,該方法會被回調(diào)。
// 響應暫停請求,暫停播放。
}
@Override
public void onPlayNext() {
super.onPlayNext();
// 當客戶端調(diào)用avController.getPlayControls().playNext()時,該方法會被回調(diào)。
// 響應播放下一曲請求,通過avSession.setAVMetadata 設置下一曲曲目的信息。
avSession.setAVMetadata(avNextMetadata);
}
// 重寫以處理按鍵事件
@Override
public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
KeyEvent ke = mediaButtonIntent.getParcelableParam(AVSession.PARAM_KEY_EVENT);
if (ke == null) {
LogUtil.error("onMediaButtonEvent", "getParcelableParam failed");
return false;
}
if (ke.isKeyDown()) {
// 只處理按鍵抬起事件
return true;
}
switch (ke.getKeyCode()) {
case KeyEvent.KEY_MEDIA_PLAY_PAUSE: {
if (playbackState.getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PAUSED) {
onPlay();
break;
}
if (playbackState.getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PLAYING) {
onPause();
break;
}
break;
}
case KeyEvent.KEY_MEDIA_PLAY: {
onPlay();
break;
}
case KeyEvent.KEY_MEDIA_PAUSE: {
onPause();
break;
}
case KeyEvent.KEY_MEDIA_STOP: {
onStop();
break;
}
case KeyEvent.KEY_MEDIA_NEXT: {
onPlayNext();
break;
}
case KeyEvent.KEY_MEDIA_PREVIOUS: {
onPlayPrevious();
break;
}
default: {
break;
}
}
return true;
}
// 其它回調(diào)方法(可選)
// ...
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: