看官方文档的话很坑, 模棱两可的. 目前最完整的官方例子只有这个: gitee.com/harmonyos_c…
1. 创建AVSession
export class ArticlePlayerManager {
player: MyAVPlayer = new MyAVPlayer("ArticlePlayerManager");
currentFmData?: FmItem = undefined;
private static instance: ArticlePlayerManager = new ArticlePlayerManager();
state: number = MyPlayState.Idle;
duration: number = 0;
private session: avSession.AVSession | null = null;
static getInstance(): ArticlePlayerManager {
return ArticlePlayerManager.instance;
}
private constructor() {
this.createSession()
}
完整的实现方法
async createSession(): Promise<void> {
if (this.session != null) {
return
}
let ret: boolean = true;
this.session = await avSession.createAVSession(getContext(this), "article_player", 'audio').catch((err: Error) => {
logE("createSession error: " + err)
ret = false;
return null
})
//监听事件
this.setListenerForMesFromController()
// 激活接口要在元数据、控制命令注册完成之后再执行
await this.session?.activate().catch((err: Error) => {
logE("activate error: " + err)
ret = false;
})
this.startContinuousTask()
}
监听事件, 你希望在状态栏里面显示哪些按钮就监听哪几个
async setListenerForMesFromController() {
if (!this.session) {
return
}
this.session.on('play', () => {
if (this.state === MyPlayState.Paused) {
ArticlePlayerManager.getInstance().resume()
} else {
ArticlePlayerManager.getInstance().play()
}
});
this.session.on('pause', () => {
ArticlePlayerManager.getInstance().pause()
});
this.session.on('stop', () => {
ArticlePlayerManager.getInstance().stop()
});
this.session.on('playNext', () => {
ArticlePlayerManager.getInstance().next()
});
this.session.on('playPrevious', () => {
ArticlePlayerManager.getInstance().pre()
});
/*this.session.on('fastForward', () => {
console.info(`on fastForward , do fastForward task`);
// 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('fastForward')取消监听
// 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
});
this.session.on('rewind', () => {
console.info(`on rewind , do rewind task`);
// 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('rewind')取消监听
// 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
});
this.session.on('seek', (time) => {
console.info(`on seek , the seek time is ${time}`);
// 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('seek')取消监听
// 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
});
this.session.on('setSpeed', (speed) => {
console.info(`on setSpeed , the speed is ${speed}`);
// do some tasks ···
});
this.session.on('setLoopMode', (mode) => {
console.info(`on setLoopMode , the loop mode is ${mode}`);
// 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('setLoopMode')取消监听
// 应用自定下一个模式,处理完毕后,请使用SetAVPlayState上报切换后的LoopMode
});
this.session.on('toggleFavorite', (assetId) => {
console.info(`on toggleFavorite , the target asset Id is ${assetId}`);
// 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('toggleFavorite')取消监听
// 处理完毕后,请使用SetAVPlayState上报收藏结果isFavorite
});*/
2. 申请后台运行
async startContinuousTask(): Promise<void> {
let wantAgentInfo: WantAgent.WantAgentInfo = {
wants: [
{
bundleName: AppUtil.getContext().abilityInfo.bundleName,
abilityName: AppUtil.getContext().abilityInfo.name
}
],
operationType: WantAgent.OperationType.START_ABILITY,
requestCode: 0,
wantAgentFlags: [WantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
let agent = await WantAgent.getWantAgent(wantAgentInfo);
backgroundTaskManager.startBackgroundRunning(getContext(this),
backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, agent).then((result) => {
logE("申请后台任务成功: " + result)
}).catch((error: Error) => {
logE("申请后台任务失败: " + error)
})
this.session?.setLaunchAbility(agent)
}
3.更新状态
需要在 AVPlayer 里面监听 player 的各种播放状态, 然后同步给通知栏
在 player 的prepared里面同步 Meta
async updateArticleToMediaSession() {
let article = this.currentFmData?.getCurrentArticle()
let metadata: avSession.AVMetadata = {
assetId: article?.objectId!,
title: article?.name,
author: article?.owner?.nickname,
mediaImage: article?.imageUrl,
description: article?.content,
duration: this.duration,
};
this.session?.setAVMetadata(metadata).then(() => {
logE(`SetAVMetadata successfully`);
}).catch((err: BusinessError) => {
logE(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
});
}
大概是这样
url: this.currentFmData?.getCurrentArticle().audioUrl,
onPrepared: () => {
EventBus.postArticlePlayState(MyPlayState.Prepared)
this.state = MyPlayState.Prepared
this.updateArticleToMediaSession()
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_BUFFERING,
})
},
onPlaying: () => {
if (this.currentFmData) {
this.currentFmData.playing = true;
}
EventBus.postArticlePlayState(MyPlayState.Playing)
this.state = MyPlayState.Playing
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
})
},
onPaused: () => {
if (this.currentFmData) {
this.currentFmData.playing = false;
}
EventBus.postArticlePlayState(MyPlayState.Paused)
this.state = MyPlayState.Paused
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
})
},
onCompleted: () => {
if (this.currentFmData) {
this.currentFmData.playing = false;
}
EventBus.postArticlePlayState(MyPlayState.Completed)
this.state = MyPlayState.Completed
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_COMPLETED,
})
},
onStopped: () => {
if (this.currentFmData) {
this.currentFmData.playing = false;
}
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_STOP,
})
},
onReleased: () => {
//AppStorage.set("state", MyPlayState.Completed)
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_RELEASED,
})
},
onProgress: (progress: number) => {
EventBus.postArticlePlayProgress(progress)
},
onTimeUpdate: (time: number) => {
EventBus.postArticlePlayTimeUpdate(time)
this.session?.setAVPlaybackState({
//state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
position: { updateTime: new Date().getTime(), elapsedTime: time }
})
},
onDuration: (duration: number) => {
EventBus.postArticlePlayDuration(duration)
this.duration = duration
this.updateArticleToMediaSession()
},
onError: (error: Error) => {
if (this.currentFmData) {
this.currentFmData.playing = false;
}
ToastUtil.showToast("播放错误: " + error.message)
EventBus.postArticlePlayError(error)
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_ERROR,
})
},
onIdle: () => {
EventBus.postArticlePlayState(MyPlayState.Idle)
this.state = MyPlayState.Idle
this.session?.setAVPlaybackState({
state: avSession.PlaybackState.PLAYBACK_STATE_IDLE,
})
},