《悬浮窗效果》三、Interface_AVPlayer使用指南
·
HarmonyOS Interface (AVPlayer) 使用指南:从入门到实战
摘要:
AVPlayer是 HarmonyOS 媒体播放的核心接口,支持音频和视频的端到端播放。本文基于 HarmonyOS NEXT开发实践,系统讲解AVPlayer的状态机模型、完整播放流程、资源加载方式和控制方法,帮助开发者快速实现音频播放功能。
效果
一、AVPlayer 概述
AVPlayer 位于 @kit.MediaKit 模块的 media 命名空间下,是 HarmonyOS 推荐的媒体播放组件。相比旧版 Player,AVPlayer 提供了更完善的状态机管理和更丰富的功能支持。
1.1 导入方式
import { media } from '@kit.MediaKit';
1.2 支持的播放源
| 播放源类型 | 说明 | 设置方式 |
|---|---|---|
| fdSrc | 本地文件描述符(rawfile资源) | avPlayer.fdSrc = { fd, offset, length } |
| url | 网络URL地址 | avPlayer.url = 'https://...' |
| dataSrc | 内存数据流 | avPlayer.dataSrc = dataSrcDescriptor |
二、状态机模型
AVPlayer 采用有限状态机设计,所有操作必须在正确的状态下调用。理解状态机是使用 AVPlayer 的关键。
2.1 状态流转图
┌──────────────────────────────────────────────┐
│ │
▼ │
[idle] ──setPlaySource──▶ [initialized] ──prepare──▶ [prepared] │
▲ │ │
│ ▼ │
│ reset() [released] ◄──release()── [stopped] ◄──play()──▶[playing]
│ ▲ ▲ │
│ │ │ ▼
│ │ stop() [paused]
│ │ │ │
│ │ │ play()│
│ │ │ │
│ │ ▼ │
│ │ [completed]───────┘
│ │ │
│ │ │ (循环播放)
│ │ ▼
│ └────────────────────── [prepared]
│
└── error ──▶ [error] ──reset()──▶ [idle]
2.2 各状态说明
| 状态 | 触发条件 | 可执行操作 |
|---|---|---|
idle |
初始状态 / reset后 / error后 | release() |
initialized |
设置播放源后(fdSrc/url) | prepare() |
prepared |
prepare成功后 | play()、seek()、setPlaybackSpeed() |
playing |
play成功后 | pause()、stop()、seek() |
paused |
pause成功后 | play()、stop()、seek() |
completed |
播放结束 | stop()、seek() |
stopped |
stop后 | prepare()(循环播放) |
released |
release后 | 不可再操作,实例已销毁 |
error |
操作出错 | reset() 回到 idle |
三、完整播放流程
3.1 创建 AVPlayer 实例
let avPlayer: media.AVPlayer = await media.createAVPlayer();
3.2 注册回调函数
必须在设置播放源之前注册回调,否则可能错过状态变化通知。
// 状态机变化回调(最核心的回调)
avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle':
// idle状态:reset后触发,可release释放资源
avPlayer.release();
break;
case 'initialized':
// initialized状态:设置播放源后触发
avPlayer.prepare(); // 准备播放
break;
case 'prepared':
// prepared状态:准备完成,可以播放
avPlayer.play(); // 开始播放
break;
case 'playing':
// 正在播放
break;
case 'paused':
// 已暂停
break;
case 'completed':
// 播放完成
avPlayer.stop(); // 停止播放
break;
case 'stopped':
// 已停止,可重新prepare循环播放
avPlayer.prepare();
break;
case 'released':
// 已释放资源
break;
}
});
// seek操作完成回调
avPlayer.on('seekDone', (seekDoneTime: number) => {
console.info(`seek完成,当前位置: ${seekDoneTime}ms`);
});
// 错误回调
avPlayer.on('error', (err) => {
console.error(`播放错误: code=${err.code}, message=${err.message}`);
avPlayer.reset(); // 出错后调用reset回到idle状态
});
3.3 设置播放源
方式一:播放 rawfile 资源(推荐用于本地音频)
import { common } from '@kit.AbilityKit';
async function playRawfileAudio(ctx: Context) {
let avPlayer = await media.createAVPlayer();
// 注册回调(省略,见3.2)
registerCallbacks(avPlayer);
// 获取rawfile资源
let context = ctx as common.UIAbilityContext;
let fileDescriptor = await context.resourceManager.getRawFd('audio.mp3');
let avFileDescriptor: media.AVFileDescriptor = {
fd: fileDescriptor.fd,
offset: fileDescriptor.offset,
length: fileDescriptor.length
};
// 设置播放源 → 触发 initialized 状态
avPlayer.fdSrc = avFileDescriptor;
}
方式二:播放网络URL
async function playUrlAudio() {
let avPlayer = await media.createAVPlayer();
// 注册回调(省略,见3.2)
registerCallbacks(avPlayer);
// 设置URL → 触发 initialized 状态
avPlayer.url = 'https://example.com/audio.mp3';
}
3.4 播放控制
// 播放
avPlayer.play();
// 暂停
avPlayer.pause();
// 停止
avPlayer.stop();
// 跳转(单位:毫秒)
avPlayer.seek(30000); // 跳转到30秒
// 释放资源
avPlayer.release();
// 重置(回到idle状态)
avPlayer.reset();
四、完整示例:音频播放服务
以下示例封装了一个完整的音频播放服务类,支持播放/暂停切换、错误处理和资源管理。
4.1 音频播放服务类
import { media } from '@kit.MediaKit';
import { common } from '@kit.AbilityKit';
import { audio } from '@kit.AudioKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
export class AudioPlayerService {
private avPlayer?: media.AVPlayer = undefined;
private currentState: string = '';
public static instance: AudioPlayerService = new AudioPlayerService();
/**
* 注册AVPlayer回调函数
*/
private registerCallbacks(avPlayer: media.AVPlayer): void {
// 状态机变化回调
avPlayer.on('stateChange', async (state: string) => {
hilog.info(0x0000, 'AudioPlayer', '状态变化: %{public}s', state);
this.currentState = state;
switch (state) {
case 'idle':
// reset后到达idle,释放资源
avPlayer.release();
break;
case 'initialized':
// 设置播放源后到达,配置音频参数并准备
avPlayer.audioRendererInfo = {
usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
rendererFlags: 0
};
avPlayer.prepare();
break;
case 'prepared':
// 准备完成,开始播放
avPlayer.play();
break;
case 'playing':
hilog.info(0x0000, 'AudioPlayer', '正在播放');
break;
case 'paused':
hilog.info(0x0000, 'AudioPlayer', '已暂停');
break;
case 'completed':
// 播放完成,停止后可重新prepare实现循环
avPlayer.stop();
break;
case 'stopped':
// 停止后重新准备,实现循环播放
avPlayer.prepare();
break;
case 'released':
hilog.info(0x0000, 'AudioPlayer', '资源已释放');
break;
}
});
// seek完成回调
avPlayer.on('seekDone', (seekDoneTime: number) => {
hilog.info(0x0000, 'AudioPlayer', 'seek完成: %{public}d', seekDoneTime);
});
// 错误回调
avPlayer.on('error', (err) => {
hilog.error(0x0000, 'AudioPlayer',
'播放错误: code=%{public}d, message=%{public}s', err.code, err.message);
avPlayer.reset();
});
}
/**
* 播放rawfile中的音频资源
*/
async playFromRawfile(ctx: Context, resourceName: string): Promise<void> {
let avPlayer = await media.createAVPlayer();
this.registerCallbacks(avPlayer);
let context = ctx as common.UIAbilityContext;
let fileDescriptor = await context.resourceManager.getRawFd(resourceName);
let avFileDescriptor: media.AVFileDescriptor = {
fd: fileDescriptor.fd,
offset: fileDescriptor.offset,
length: fileDescriptor.length
};
avPlayer.fdSrc = avFileDescriptor;
this.avPlayer = avPlayer;
}
/**
* 切换播放/暂停
*/
togglePlayPause(ctx: Context, resourceName: string): void {
if (this.avPlayer === undefined) {
// 首次播放,创建播放器
this.playFromRawfile(ctx, resourceName);
} else if (this.currentState === 'playing') {
this.avPlayer.pause();
} else {
this.avPlayer.play();
}
}
/**
* 获取当前状态
*/
getState(): string {
return this.currentState;
}
}
4.2 在组件中使用
import { AudioPlayerService } from '../utils/AudioPlayerService';
@Entry
@Component
struct AudioPage {
@Local isPlaying: boolean = false;
private ctx?: Context = this.getUIContext().getHostContext();
build() {
Column({ space: 20 }) {
Text('AVPlayer 音频播放示例')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(this.isPlaying ? '正在播放...' : '已暂停')
.fontSize(16)
.fontColor(this.isPlaying ? '#4CAF50' : '#999999')
Button(this.isPlaying ? '暂停' : '播放')
.fontSize(16)
.onClick(() => {
AudioPlayerService.instance.togglePlayPause(
this.ctx!, 'sample.wav');
this.isPlaying = !this.isPlaying;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
五、音频渲染参数配置
5.1 audioRendererInfo
在 initialized 状态下设置音频渲染参数:
avPlayer.audioRendererInfo = {
// 音频流使用类型
usage: audio.StreamUsage.STREAM_USAGE_MUSIC, // 音乐
// rendererFlags: 0 // 音频渲染器标志
};
常用 StreamUsage 类型:
| 类型 | 说明 |
|---|---|
STREAM_USAGE_MUSIC |
音乐播放 |
STREAM_USAGE_VOICE_COMMUNICATION |
语音通话 |
STREAM_USAGE_NOTIFICATION |
通知提示音 |
STREAM_USAGE_ALARM |
闹钟 |
STREAM_USAGE_GAME |
游戏音效 |
5.2 其他播放参数
// 设置音量(0.0 ~ 1.0)
avPlayer.volume = 0.8;
// 设置播放速度(0.5x ~ 2.0x)
avPlayer.setPlaybackSpeed(1.5);
// 设置循环模式(需要手动在completed状态处理)
// AVPlayer本身不直接支持循环,需在stateChange回调中实现
六、开发要点与最佳实践
6.1 回调注册时机
正确顺序:
1. createAVPlayer() → 创建实例
2. on('stateChange') → 注册状态回调 ★ 必须在设置播放源之前
3. on('error') → 注册错误回调 ★ 必须在设置播放源之前
4. fdSrc / url → 设置播放源(触发状态机流转)
错误顺序:
1. createAVPlayer()
2. fdSrc → ✗ 可能错过 initialized 状态
3. on('stateChange') → ✗ 已来不及接收状态变化
6.2 错误处理策略
avPlayer.on('error', (err) => {
// 1. 记录错误日志
hilog.error(0x0000, 'AVPlayer', '错误: %{public}s', JSON.stringify(err));
// 2. 调用reset回到idle状态
avPlayer.reset();
// 3. 在idle状态的stateChange回调中release释放资源
});
6.3 资源释放
// 正确的资源释放流程
avPlayer.stop(); // 先停止
// → stopped 状态
// 在 stateChange 的 idle 回调中:
avPlayer.release(); // 释放资源
// → released 状态,实例不可再使用
6.4 循环播放实现
AVPlayer 不直接支持循环播放,需要在状态机回调中手动实现:
avPlayer.on('stateChange', async (state: string) => {
if (state === 'completed') {
avPlayer.stop(); // 播放完成后停止
// → stopped 状态
}
if (state === 'stopped') {
avPlayer.prepare(); // 停止后重新准备
// → prepared 状态 → play() 自动播放
}
});
6.5 单例模式管理
推荐使用单例模式管理 AVPlayer 实例,避免创建多个播放器:
export class AudioPlayerService {
public static instance: AudioPlayerService = new AudioPlayerService();
private avPlayer?: media.AVPlayer;
// 确保全局只有一个播放器实例
}
七、AVPlayer 回调事件速查表
| 事件名 | 说明 | 回调参数 |
|---|---|---|
stateChange |
状态机变化 | (state: string, reason: StateChangeReason) |
seekDone |
seek操作完成 | (seekDoneTime: number) |
error |
操作出错 | (err: BusinessError) |
timeUpdate |
播放时间更新 | (time: number) |
durationUpdate |
总时长更新 | (duration: number) |
bufferingUpdate |
缓冲更新 | (infoType: BufferingInfoType, value: number) |
audioInterruptBegin |
音频焦点被抢占开始 | () |
audioInterruptEnd |
音频焦点恢复 | () |
八、总结
AVPlayer 是 HarmonyOS 媒体播放的核心组件,掌握以下要点即可应对大部分音频播放场景:
- 状态机模型:理解 idle → initialized → prepared → playing → paused → completed → stopped 的完整流转
- 回调注册:必须在设置播放源之前注册
stateChange和error回调 - 播放源设置:支持 fdSrc(本地资源)、url(网络地址)、dataSrc(内存数据)
- 播放控制:play、pause、stop、seek、release、reset
- 错误处理:error 状态下调用 reset 回到 idle,再 release 释放资源
- 循环播放:在 completed → stop → prepare 链路中实现
相关文档:
更多推荐


所有评论(0)