本文汇总音视频应用在本地媒体会话接入AVSession Kit简介过程中遇到的典型问题及其定位与解决方法。开发者可结合媒体会话管理错误码和HiLog日志进一步定位问题。
问题现象
调用createAVSession抛出异常,会话未创建成功。
可能原因
解决措施
确认是否已经存在存活的AVSession,必要时先调用destroy释放旧会话后再创建。在创建前还可以通过getAVSession接口判断当前应用是否已经创建过会话对象,再决定是否销毁旧会话或直接复用已有会话。
频繁创建和销毁场景下,通过媒体会话控制器监听on('sessionDestroy')事件,待收到旧会话销毁回调后再创建新的AVSession对象。
import { avSession } from '@kit.AVSessionKit';
async destroyAndRecreateAVSession(context: Context) {
let videoSession: avSession.AVSession;
let avSessionController: avSession.AVSessionController;
try {
// 第一次创建AVSession,并获取其控制器。
videoSession = await avSession.createAVSession(context, 'VIDEO_SESSION', 'video');
avSessionController = await videoSession.getController();
// 注册会话销毁监听,会话销毁后触发回调。
avSessionController.on('sessionDestroy', async () => {
// 第二次创建AVSession,销毁后重新创建同类型会话。
videoSession = await avSession.createAVSession(context, 'VIDEO_SESSION', 'video');
// 第二次销毁AVSession。
await videoSession.destroy();
});
// 第一次销毁AVSession,触发上述sessionDestroy回调。
await videoSession.destroy();
} catch (err) {
console.error(`AVSession create Error: Code: ${err.code}, message: ${err.message}`);
}
} 推荐通过this.getUIContext().getHostContext() as Context获取context,避免传入undefined或非当前UIAbility的上下文。
确保type为AVSessionType定义的合法取值。
确保所有必填参数均为合法非空值,例如tag避免传入空字符串等无效值。
问题现象
应用切到后台后,音视频播放被系统强制暂停,用户无法继续收听。
可能原因
解决措施
参考后台播放中的接入AVSession完成AVSession接入。
申请AUDIO_PLAYBACK类型长时任务(ArkTS)。
使用类成员变量保存session实例,并在应用进程结束或退出播放业务时再释放。
参考创建AVSession失败中的相关原因逐一排查,确保应用持有有效会话。
应用退至后台前通过setBackgroundPlayMode设置后台播放模式(BackgroundPlayMode),告知系统应用退至后台时是否继续播放:
其中AVSessionType为audio类型的应用默认值为ENABLE_BACKGROUND_PLAY;video类型的应用默认值为DISABLE_BACKGROUND_PLAY。如果视频类应用希望支持后台放音,需显式设置为ENABLE_BACKGROUND_PLAY;如果应用内提供了"是否支持后台播放"的开关,设置的后台播放模式务必与开关状态保持一致,否则可能导致退后台后被强制暂停或系统实况窗展示错误。设置示例如下:
import { avSession } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// 假设已创建并持有currentAVSession。
async setBackgroundPlayMode(currentAVSession: avSession.AVSession) {
try {
await currentAVSession.setBackgroundPlayMode(avSession.BackgroundPlayMode.ENABLE_BACKGROUND_PLAY);
console.info(' Succeeded in setBackgroundPlayMode');
} catch (err) {
let error = err as BusinessError;
console.error(`setBackgroundPlayMode BusinessError: code: ${error.code}, message: ${error.message}`);
}
} 更多说明请参考设置后台播放模式。
问题现象
应用已创建AVSession,但播控中心未展示对应媒体信息或控制条。
可能原因
通话类应用未使用通话会话类型,或系统版本/应用分类不满足要求。
在HarmonyOS 6.0.0以下版本,通话类应用接入AVSession不会在播控中心展示。
解决措施
通话类应用接入AVSession时,会话类型(AVSessionType)需选择voice_call或video_call。
在HarmonyOS 6.0.0及以上版本,当应用在应用市场上架为商务或社交应用时,可在播控中心显示"正在通话中...",并支持通过AVCastPicker组件切换通话设备,具体可参考切换通话输出设备。
问题现象
播控中心点击控制按钮(播放、暂停、上一首、下一首等)无响应,且应用与播控界面均未更新;或应用实际播放状态与播控中心显示状态不同步,如应用正在播放,播控仍显示为暂停。
可能原因
解决措施
问题现象
在播控中心点击播放按钮后,播控进度条发生回退闪烁。
可能原因
播放器起播延迟导致进度不一致。点击播放后播控进度条即开始计时,而应用内播放器尚未真正起播,进度落后于播控。应用随后同步进度时,因进度小于播控已计时进度,导致进度条回退闪烁。
解决措施
在播放器起播前,先通过setAVPlaybackState将状态置为PLAYBACK_STATE_BUFFERING(缓冲),待真正起播后再同步状态与进度。
import { avSession } from '@kit.AVSessionKit';
import { media } from '@kit.MediaKit';
// avPlayer为通过media.createAVPlayer()创建的播放器实例,currentAVSession为已创建的AVSession对象。
async listenAVPlayer(avPlayer: media.AVPlayer, currentAVSession: avSession.AVSession) {
// 预先监听AVPlayer状态机切换,真正起播(进入playing状态)后,再同步真实状态与进度。
avPlayer.on('stateChange', async (state: string) => {
if (state === 'playing') {
let playingState: avSession.AVPlaybackState = {
state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
speed: 1.0,
// currentTime为AVPlayer当前真实播放进度,单位为毫秒(ms)。
position: { elapsedTime: avPlayer.currentTime, updateTime: (new Date()).getTime() }
};
await currentAVSession.setAVPlaybackState(playingState);
}
});
// 收到播放命令后、AVPlayer真正起播前,先将播控状态置为缓冲,避免播控进度条先行计时。
let bufferingState: avSession.AVPlaybackState = {
state: avSession.PlaybackState.PLAYBACK_STATE_BUFFERING,
speed: 0,
position: { elapsedTime: 0, updateTime: (new Date()).getTime() }
};
await currentAVSession.setAVPlaybackState(bufferingState);
await avPlayer.play();
}