HarmonyOS鸿蒙Next中使用AVPlayer播放音频后,切换音频文件播放报错
HarmonyOS鸿蒙Next中使用AVPlayer播放音频后,切换音频文件播放报错
AVPlayer.reset前加个await就行了
export class AudioPlayUtils {
private avPlayer: media.AVPlayer | null = null;
constructor() {
media.createAVPlayer().then(async (avPlayer: media.AVPlayer) => {
this.avPlayer = avPlayer;
this.playerCallback(avPlayer);
})
}
async audioPrepare(mediaUrl: string) {
let fileDescriptor = await getContext().resourceManager.getRawFd(mediaUrl);
let avFileDescriptor: media.AVFileDescriptor =
{ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
if (this.avPlayer) {
this.avPlayer.stop()
this.avPlayer.reset()
this.avPlayer.fdSrc = avFileDescriptor
}
}
audioPlay() {
this.avPlayer?.play()
}
audioPause() {
this.avPlayer?.pause()
}
release() {
this.avPlayer?.release()
}
// 注册avplayer回调函数
playerCallback(avPlayer: media.AVPlayer) {
avPlayer.on('timeUpdate', (time: number) => {
// console.info(TAG, 'AVPlayer timeUpdate. time = ' + time / 1000);
})
// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
avPlayer.on('error', (err: BusinessError) => {
console.error(TAG, `Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
avPlayer.reset(); // 调用reset重置资源,触发idle状态
})
// 状态机变化回调函数
avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle': // 成功调用reset接口后触发该状态机上报
console.info(TAG, 'AVPlayer state idle called.');
break;
case 'initialized': // avplayer 设置播放源后触发该状态上报
console.info(TAG, 'AVPlayer state initialized called.');
if (this.avPlayer) {
avPlayer.prepare();
}
break;
case 'prepared': // prepare调用成功后上报该状态机
console.info(TAG, 'AVPlayer state prepared called.');
avPlayer.play()
break;
case 'completed': // prepare调用成功后上报该状态机
console.info(TAG, 'AVPlayer state completed called.');
avPlayer.stop();
break;
case 'playing': // play成功调用后触发该状态机上报
console.info(TAG, 'AVPlayer state playing called.');
break;
case 'paused': // pause成功调用后触发该状态机上报
console.info(TAG, 'AVPlayer state paused called.');
break;
case 'stopped': // stop接口成功调用后触发该状态机上报
console.info(TAG, 'AVPlayer state stopped called.');
avPlayer.reset();
break;
case 'released':
console.info(TAG, 'AVPlayer state released called.');
break;
default:
console.info(TAG, 'AVPlayer state unknown called.');
break;
}
})
}
}
调用处
playUtils: AudioPlayUtils = new AudioPlayUtils()
this.playUtils.audioPrepare(rawFile文件)
我想使用一个avPlay对象,使用audioPrepare切换其他音频源,而不用销毁avPlay重新创建,但是会报错5400102或者401
更多关于HarmonyOS鸿蒙Next中使用AVPlayer播放音频后,切换音频文件播放报错的实战教程也可以访问 https://www.itying.com/category-93-b0.html
2 回复
HarmonyOS鸿蒙Next中AVPlayer切换音频报错可能由以下原因导致:
- 未正确释放前一个player实例,需调用release()释放资源
- 未重置播放器状态,切换前应先调用reset()
- 文件路径或格式不兼容,确认新音频为支持的格式(AAC/MP3等)
- 未正确设置新数据源,需通过setSource()重新配置
标准处理流程:
- player.reset()
- player.setSource(newSource)
- player.prepare()
- player.play()
注意检查错误回调中的具体错误码,常见有MEDIA_ERROR_UNSUPPORTED(901)和MEDIA_ERROR_INVALID_OPERATION(540)。
更多关于HarmonyOS鸿蒙Next中使用AVPlayer播放音频后,切换音频文件播放报错的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中使用AVPlayer切换音频源时出现5400102或401错误,主要是由于状态管理不当导致的。以下是关键点分析:
- 主要问题在于
reset()
操作是异步的,但代码中没有等待其完成就立即设置新源。应该在audioPrepare
方法中添加await:
async audioPrepare(mediaUrl: string) {
let fileDescriptor = await getContext().resourceManager.getRawFd(mediaUrl);
let avFileDescriptor: media.AVFileDescriptor =
{ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
if (this.avPlayer) {
this.avPlayer.stop();
await this.avPlayer.reset(); // 关键修改:添加await
this.avPlayer.fdSrc = avFileDescriptor;
}
}
- 错误代码说明:
- 5400102:通常表示在错误状态下调用了API
- 401:表示无效操作,通常发生在状态转换未完成时
- 状态机注意事项:
- 必须在"idle"状态才能设置新源
- reset()操作会触发状态回到idle
- 所有状态转换都需要时间,必须通过await确保顺序执行
- 其他建议:
- 在error回调中不要直接调用reset(),这可能导致循环
- 考虑在stateChange回调中处理状态转换逻辑更可靠
这个修改能确保reset操作完成后再设置新源,避免状态冲突导致的错误。