鸿蒙Media Kit媒体服务开发快速指南
Media Kit是HarmonyOS提供的媒体服务框架,提供音视频播放、录制、编解码等全方位的媒体处理能力。功能模块主要API适用场景音频播放AVPlayer播放完整音频文件短音播放SoundPool低时延音效播放视频播放AVPlayer播放视频文件音频录制录制音频视频录制录制视频后台播放AVSession + 长时任务后台音乐播放✅ 根据场景选择合适的API✅ 正确处理播放器状态转换✅ 做好错
一、Media Kit概述
Media Kit是HarmonyOS提供的媒体服务框架,提供音视频播放、录制、编解码等全方位的媒体处理能力。
1.1 核心能力
| 能力类型 | 说明 | 主要API |
|---|---|---|
| 音频播放 | 播放各种格式音频文件 | AVPlayer, SoundPool, AudioRenderer |
| 视频播放 | 播放各种格式视频文件 | AVPlayer, Video组件 |
| 音频录制 | 录制音频 | AVRecorder, AudioCapturer |
| 视频录制 | 录制视频 | AVRecorder |
| 音视频解码 | 解码音视频数据 | AVDemuxer, AVDecoder |
| 音视频编码 | 编码音视频数据 | AVMuxer, AVEncoder |
1.2 选择合适的API
音频播放场景:
简短音效<5s
完整音频文件
PCM数据流
音振协同
选择音频播放API
场景判断
SoundPool
AVPlayer
AudioRenderer
AudioHaptic
低时延播放
支持多种格式
需要预处理
铃声/反馈
视频播放场景:
- AVPlayer: 功能完善,支持多种格式,适合专业视频播放
- Video组件: UI组件封装,简单易用,适合快速开发
二、音频播放开发
2.1 使用AVPlayer播放音频
AVPlayer适用于播放完整的音频文件,支持mp3、m4a、flac等格式。
2.1.1 AVPlayer状态机
createAVPlayer()
url设置
prepare()
play()
pause()
play()
stop()
prepare()
release()
release()
idle
initialized
prepared
playing
paused
stopped
released
2.1.2 完整示例
import { media } from '@kit.MediaKit'; import { BusinessError } from '@kit.BasicServicesKit'; class AudioPlayer { private avPlayer: media.AVPlayer | undefined = undefined; async init() { // 1. 创建AVPlayer实例 this.avPlayer = await media.createAVPlayer(); // 2. 设置状态变化监听 this.avPlayer.on('stateChange', (state: string, reason: media.StateChangeReason) => { console.info(`AVPlayer state changed to: ${state}, reason: ${reason}`); }); // 3. 设置错误监听 this.avPlayer.on('error', (error: BusinessError) => { console.error(`AVPlayer error: ${error.code}, ${error.message}`); }); // 4. 监听播放进度 this.avPlayer.on('timeUpdate', (time: number) => { console.info(`Current time: ${time}ms`); }); // 5. 监听播放完成 this.avPlayer.on('durationUpdate', (duration: number) => { console.info(`Total duration: ${duration}ms`); }); } async playAudio(url: string) { if (!this.avPlayer) { return; } try { // 设置音频资源 this.avPlayer.url = url; // 准备播放 await this.avPlayer.prepare(); // 开始播放 await this.avPlayer.play(); } catch (err) { let error = err as BusinessError; console.error(`Play failed: ${error.code}, ${error.message}`); } } async pause() { if (this.avPlayer && this.avPlayer.state === 'playing') { await this.avPlayer.pause(); } } async resume() { if (this.avPlayer && this.avPlayer.state === 'paused') { await this.avPlayer.play(); } } async seek(time: number) { if (this.avPlayer) { await this.avPlayer.seek(time, media.SeekMode.SEEK_PREV_SYNC); } } async stop() { if (this.avPlayer) { await this.avPlayer.stop(); } } async release() { if (this.avPlayer) { await this.avPlayer.release(); this.avPlayer = undefined; } } } // 使用示例 let player = new AudioPlayer(); await player.init(); await player.playAudio('https://example.com/audio.mp3');
2.2 使用SoundPool播放短音
SoundPool适用于播放低时延的短音效,如按键音、提示音等。
2.2.1 工作流程
应用SoundPool解码器音频系统createSoundPool()load(fd)解码音频解码完成on('loadComplete')play(soundId)播放音频播放完成on('playFinished')应用SoundPool解码器音频系统
2.2.2 代码示例
import { media } from '@kit.MediaKit'; import { audio } from '@kit.AudioKit'; import { BusinessError } from '@kit.BasicServicesKit'; class SoundEffectPlayer { private soundPool: media.SoundPool | undefined = undefined; private soundId: number = 0; private streamId: number = 0; async init() { // 1. 配置音频渲染信息 let audioRendererInfo: audio.AudioRendererInfo = { usage: audio.StreamUsage.STREAM_USAGE_MUSIC, rendererFlags: 1 }; // 2. 创建SoundPool实例,最大支持14个并发流 this.soundPool = await media.createSoundPool(14, audioRendererInfo); // 3. 监听资源加载完成 this.soundPool.on('loadComplete', (soundId: number) => { this.soundId = soundId; console.info(`Sound loaded: ${soundId}`); }); // 4. 监听播放完成 this.soundPool.on('playFinishedWithStreamId', (streamId: number) => { console.info(`Play finished: ${streamId}`); }); // 5. 监听错误 this.soundPool.on('error', (error: BusinessError) => { console.error(`SoundPool error: ${error.code}`); }); } async loadSound(fd: number, offset: number, length: number) { if (this.soundPool) { this.soundId = await this.soundPool.load(fd, offset, length); } } async playSound() { if (!this.soundPool) { return; } let playParameters: media.PlayParameters = { loop: 0, // 不循环 rate: 1, // 正常速度 leftVolume: 1.0, rightVolume: 1.0, priority: 0 }; this.soundPool.play(this.soundId, playParameters, (error, streamId: number) => { if (error) { console.error(`Play error: ${error.code}`); } else { this.streamId = streamId; console.info(`Playing stream: ${streamId}`); } }); } async release() { if (this.soundPool) { await this.soundPool.off('loadComplete'); await this.soundPool.off('playFinishedWithStreamId'); await this.soundPool.off('error'); await this.soundPool.release(); this.soundPool = undefined; } } } // 使用示例 let soundPlayer = new SoundEffectPlayer(); await soundPlayer.init(); // 从rawfile加载音频 let context = getContext(this); let fileDescriptor = await context.resourceManager.getRawFd('click.ogg'); await soundPlayer.loadSound(fileDescriptor.fd, fileDescriptor.offset, fileDescriptor.length); await soundPlayer.playSound();
三、视频播放开发
3.1 AVPlayer视频播放
视频播放在音频播放基础上增加了视窗显示功能。
3.1.1 关键步骤
应用AVPlayerXComponent视频系统createAVPlayer()设置监听url = videoUrl获取surfaceIdsurfaceIdsurfaceId = idprepare()初始化视频管道play()渲染视频帧显示画面应用AVPlayerXComponent视频系统
3.1.2 完整代码示例
import { media } from '@kit.MediaKit'; import { BusinessError } from '@kit.BasicServicesKit'; @Entry @Component struct VideoPlayer { private avPlayer: media.AVPlayer | undefined = undefined; private surfaceId: string = ''; @State isPlaying: boolean = false; @State currentTime: number = 0; @State duration: number = 0; async aboutToAppear() { await this.initPlayer(); } async initPlayer() { // 1. 创建AVPlayer this.avPlayer = await media.createAVPlayer(); // 2. 设置状态监听 this.avPlayer.on('stateChange', (state: string, reason: media.StateChangeReason) => { console.info(`State: ${state}`); if (state === 'playing') { this.isPlaying = true; } else if (state === 'paused' || state === 'stopped') { this.isPlaying = false; } }); // 3. 设置错误监听 this.avPlayer.on('error', (error: BusinessError) => { console.error(`Error: ${error.code}`); }); // 4. 监听时长 this.avPlayer.on('durationUpdate', (duration: number) => { this.duration = duration; }); // 5. 监听进度 this.avPlayer.on('timeUpdate', (time: number) => { this.currentTime = time; }); // 6. 监听视频尺寸变化 this.avPlayer.on('videoSizeChange', (width: number, height: number) => { console.info(`Video size: ${width}x${height}`); }); // 7. 监听首帧渲染 this.avPlayer.on('startRenderFrame', () => { console.info('First frame rendered'); }); } async playVideo(url: string) { if (!this.avPlayer || !this.surfaceId) { return; } try { // 设置视频URL this.avPlayer.url = url; // 设置窗口 this.avPlayer.surfaceId = this.surfaceId; // 准备播放 await this.avPlayer.prepare(); // 开始播放 await this.avPlayer.play(); } catch (err) { let error = err as BusinessError; console.error(`Play failed: ${error.message}`); } } async pauseVideo() { if (this.avPlayer && this.isPlaying) { await this.avPlayer.pause(); } } async resumeVideo() { if (this.avPlayer && !this.isPlaying) { await this.avPlayer.play(); } } async seekTo(time: number) { if (this.avPlayer) { await this.avPlayer.seek(time); } } formatTime(ms: number): string { let seconds = Math.floor(ms / 1000); let minutes = Math.floor(seconds / 60); let remainingSeconds = seconds % 60; return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; } build() { Column() { // 视频显示区域 XComponent({ id: 'video_player', type: XComponentType.SURFACE, controller: new XComponentController() }) .onLoad((context) => { // 获取surfaceId this.surfaceId = context.getXComponentSurfaceId(); // 播放视频 this.playVideo('https://example.com/video.mp4'); }) .width('100%') .height(300) // 播放控制区域 Row({ space: 20 }) { // 播放/暂停按钮 Button(this.isPlaying ? '暂停' : '播放') .onClick(() => { if (this.isPlaying) { this.pauseVideo(); } else { this.resumeVideo(); } }) // 进度显示 Text(`${this.formatTime(this.currentTime)} / ${this.formatTime(this.duration)}`) .fontSize(14) } .width('90%') .margin({ top: 20 }) // 进度条 Slider({ value: this.currentTime, min: 0, max: this.duration, step: 1000 }) .width('90%') .onChange((value: number) => { this.seekTo(value); }) } .width('100%') .height('100%') } aboutToDisappear() { if (this.avPlayer) { this.avPlayer.release(); } } }
四、音频录制开发
4.1 使用AudioCapturer录制音频
AudioCapturer用于采集PCM音频数据。
import { audio } from '@kit.AudioKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { fileIo as fs } from '@kit.CoreFileKit'; class AudioRecorder { private audioCapturer: audio.AudioCapturer | undefined = undefined; private audioFile: fs.File | undefined = undefined; async init() { // 1. 配置音频采集参数 let audioStreamInfo: audio.AudioStreamInfo = { samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, channels: audio.AudioChannel.CHANNEL_2, sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW }; let audioCapturerInfo: audio.AudioCapturerInfo = { source: audio.SourceType.SOURCE_TYPE_MIC, capturerFlags: 0 }; let audioCapturerOptions: audio.AudioCapturerOptions = { streamInfo: audioStreamInfo, capturerInfo: audioCapturerInfo }; // 2. 创建AudioCapturer this.audioCapturer = await audio.createAudioCapturer(audioCapturerOptions); // 3. 监听状态变化 this.audioCapturer.on('stateChange', (state: audio.AudioState) => { console.info(`AudioCapturer state: ${state}`); }); } async startRecording(filePath: string) { if (!this.audioCapturer) { return; } try { // 创建文件 this.audioFile = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 启动录制 await this.audioCapturer.start(); // 读取音频数据并写入文件 let bufferSize = await this.audioCapturer.getBufferSize(); let buffer = await this.audioCapturer.read(bufferSize, true); fs.writeSync(this.audioFile.fd, buffer); } catch (err) { let error = err as BusinessError; console.error(`Recording failed: ${error.message}`); } } async stopRecording() { if (this.audioCapturer) { await this.audioCapturer.stop(); await this.audioCapturer.release(); } if (this.audioFile) { fs.closeSync(this.audioFile); } } }
五、视频录制开发
5.1 使用AVRecorder录制视频
AVRecorder集成了音视频采集、编码、封装功能。
5.1.1 录制状态机
createAVRecorder()
prepare()
start()
pause()
resume()
stop()
prepare()
release()
idle
prepared
started
paused
stopped
released
5.1.2 代码示例
import { media } from '@kit.MediaKit'; import { camera } from '@kit.CameraKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { fileIo as fs } from '@kit.CoreFileKit'; class VideoRecorder { private avRecorder: media.AVRecorder | undefined = undefined; private videoFile: fs.File | undefined = undefined; async init() { // 1. 创建AVRecorder this.avRecorder = await media.createAVRecorder(); // 2. 设置状态监听 this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => { console.info(`AVRecorder state: ${state}, reason: ${reason}`); }); // 3. 设置错误监听 this.avRecorder.on('error', (error: BusinessError) => { console.error(`AVRecorder error: ${error.code}`); }); } async startRecording(context: Context) { if (!this.avRecorder) { return; } try { // 1. 创建录制文件 let filePath = context.filesDir + '/video.mp4'; this.videoFile = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 2. 配置录制参数 let avProfile: media.AVRecorderProfile = { fileFormat: media.ContainerFormatType.CFT_MPEG_4, videoBitrate: 2000000, videoCodec: media.CodecMimeType.VIDEO_AVC, videoFrameWidth: 1920, videoFrameHeight: 1080, videoFrameRate: 30 }; let avConfig: media.AVRecorderConfig = { videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, profile: avProfile, url: 'fd://' + this.videoFile.fd, metadata: { videoOrientation: '0' } }; // 3. 准备录制 await this.avRecorder.prepare(avConfig); // 4. 获取Surface用于相机输入 let surfaceId = await this.avRecorder.getInputSurface(); // 5. 初始化相机(省略相机初始化代码) // await this.initCamera(surfaceId); // 6. 开始录制 await this.avRecorder.start(); } catch (err) { let error = err as BusinessError; console.error(`Start recording failed: ${error.message}`); } } async pauseRecording() { if (this.avRecorder && this.avRecorder.state === 'started') { await this.avRecorder.pause(); } } async resumeRecording() { if (this.avRecorder && this.avRecorder.state === 'paused') { await this.avRecorder.resume(); } } async stopRecording() { if (this.avRecorder) { await this.avRecorder.stop(); await this.avRecorder.release(); } if (this.videoFile) { fs.closeSync(this.videoFile); } } }
六、实战示例:多媒体播放器应用
6.1 应用架构
MediaPlayerApp/ ├── entry/ │ └── src/main/ │ ├── ets/ │ │ ├── entryability/ │ │ │ └── EntryAbility.ets │ │ ├── pages/ │ │ │ ├── Index.ets (首页) │ │ │ ├── AudioPlayer.ets (音频播放器) │ │ │ └── VideoPlayer.ets (视频播放器) │ │ └── model/ │ │ ├── MediaManager.ets (媒体管理器) │ │ └── PlaylistModel.ets (播放列表) │ └── resources/ │ └── rawfile/ │ ├── audio/ │ └── video/
6.2 媒体管理器实现
import { media } from '@kit.MediaKit'; import { BusinessError } from '@kit.BasicServicesKit'; export interface MediaItem { id: string; title: string; url: string; duration: number; type: 'audio' | 'video'; } export class MediaManager { private avPlayer: media.AVPlayer | undefined = undefined; private currentMedia: MediaItem | null = null; private onStateChange?: (state: string) => void; private onTimeUpdate?: (time: number) => void; private onDurationUpdate?: (duration: number) => void; async init() { this.avPlayer = await media.createAVPlayer(); // 状态变化监听 this.avPlayer.on('stateChange', (state: string, reason: media.StateChangeReason) => { console.info(`State changed to: ${state}`); if (this.onStateChange) { this.onStateChange(state); } }); // 错误监听 this.avPlayer.on('error', (error: BusinessError) => { console.error(`Player error: ${error.code}, ${error.message}`); }); // 时长更新 this.avPlayer.on('durationUpdate', (duration: number) => { if (this.onDurationUpdate) { this.onDurationUpdate(duration); } }); // 进度更新 this.avPlayer.on('timeUpdate', (time: number) => { if (this.onTimeUpdate) { this.onTimeUpdate(time); } }); } setStateChangeListener(callback: (state: string) => void) { this.onStateChange = callback; } setTimeUpdateListener(callback: (time: number) => void) { this.onTimeUpdate = callback; } setDurationUpdateListener(callback: (duration: number) => void) { this.onDurationUpdate = callback; } async playMedia(media: MediaItem, surfaceId?: string) { if (!this.avPlayer) { return; } try { this.currentMedia = media; this.avPlayer.url = media.url; if (media.type === 'video' && surfaceId) { this.avPlayer.surfaceId = surfaceId; } await this.avPlayer.prepare(); await this.avPlayer.play(); } catch (err) { let error = err as BusinessError; console.error(`Play media failed: ${error.message}`); } } async pause() { if (this.avPlayer && this.avPlayer.state === 'playing') { await this.avPlayer.pause(); } } async resume() { if (this.avPlayer && this.avPlayer.state === 'paused') { await this.avPlayer.play(); } } async seek(time: number) { if (this.avPlayer) { await this.avPlayer.seek(time, media.SeekMode.SEEK_PREV_SYNC); } } async stop() { if (this.avPlayer) { await this.avPlayer.stop(); this.currentMedia = null; } } async release() { if (this.avPlayer) { await this.avPlayer.release(); this.avPlayer = undefined; } } getCurrentMedia(): MediaItem | null { return this.currentMedia; } getState(): string { return this.avPlayer?.state || 'idle'; } }
6.3 音频播放器页面
import { MediaManager, MediaItem } from '../model/MediaManager'; @Entry @Component struct AudioPlayerPage { @State playlist: MediaItem[] = []; @State currentIndex: number = 0; @State isPlaying: boolean = false; @State currentTime: number = 0; @State duration: number = 0; private mediaManager: MediaManager = new MediaManager(); async aboutToAppear() { // 初始化媒体管理器 await this.mediaManager.init(); // 设置监听回调 this.mediaManager.setStateChangeListener((state: string) => { this.isPlaying = (state === 'playing'); }); this.mediaManager.setTimeUpdateListener((time: number) => { this.currentTime = time; }); this.mediaManager.setDurationUpdateListener((duration: number) => { this.duration = duration; }); // 加载播放列表 this.loadPlaylist(); } loadPlaylist() { this.playlist = [ { id: '1', title: '音乐1', url: 'https://example.com/music1.mp3', duration: 0, type: 'audio' }, { id: '2', title: '音乐2', url: 'https://example.com/music2.mp3', duration: 0, type: 'audio' } ]; } async playAudio(index: number) { if (index >= 0 && index < this.playlist.length) { this.currentIndex = index; await this.mediaManager.playMedia(this.playlist[index]); } } async togglePlayPause() { if (this.isPlaying) { await this.mediaManager.pause(); } else { await this.mediaManager.resume(); } } async playNext() { let nextIndex = (this.currentIndex + 1) % this.playlist.length; await this.playAudio(nextIndex); } async playPrevious() { let prevIndex = (this.currentIndex - 1 + this.playlist.length) % this.playlist.length; await this.playAudio(prevIndex); } formatTime(ms: number): string { let totalSeconds = Math.floor(ms / 1000); let minutes = Math.floor(totalSeconds / 60); let seconds = totalSeconds % 60; return `${minutes}:${seconds.toString().padStart(2, '0')}`; } build() { Column() { // 顶部导航 Row() { Text('音频播放器') .fontSize(24) .fontWeight(FontWeight.Bold) } .width('100%') .padding(20) .backgroundColor('#f0f0f0') // 播放列表 List({ space: 10 }) { ForEach(this.playlist, (item: MediaItem, index: number) => { ListItem() { Row() { Text(item.title) .fontSize(16) .layoutWeight(1) .fontColor(index === this.currentIndex ? '#007DFF' : '#000') if (index === this.currentIndex) { Text(this.isPlaying ? '播放中' : '已暂停') .fontSize(12) .fontColor('#666') } } .width('100%') .padding(15) .backgroundColor(index === this.currentIndex ? '#e6f2ff' : '#fff') .borderRadius(8) } .onClick(() => { this.playAudio(index); }) }, (item: MediaItem) => item.id) } .width('90%') .layoutWeight(1) .margin({ top: 20 }) // 播放控制区域 Column({ space: 20 }) { // 当前播放信息 Text(this.currentIndex >= 0 ? this.playlist[this.currentIndex].title : '未选择') .fontSize(18) .fontWeight(FontWeight.Medium) // 进度条 Column({ space: 10 }) { Slider({ value: this.currentTime, min: 0, max: this.duration, step: 1000 }) .width('100%') .onChange((value: number) => { this.mediaManager.seek(value); }) Row() { Text(this.formatTime(this.currentTime)) .fontSize(12) Blank() Text(this.formatTime(this.duration)) .fontSize(12) } .width('100%') } .width('100%') // 控制按钮 Row({ space: 30 }) { Button('上一首') .onClick(() => this.playPrevious()) Button(this.isPlaying ? '暂停' : '播放') .onClick(() => this.togglePlayPause()) .width(80) Button('下一首') .onClick(() => this.playNext()) } .width('100%') .justifyContent(FlexAlign.Center) } .width('90%') .padding(20) .backgroundColor('#f8f8f8') .borderRadius(10) .margin({ bottom: 20 }) } .width('100%') .height('100%') .backgroundColor('#fff') } aboutToDisappear() { this.mediaManager.release(); } }
七、后台播放与媒体会话
7.1 实现后台播放
要实现后台播放或熄屏播放,需要:
- 注册AVSession(媒体会话)
- 申请长时任务
import { AVSessionManager } from '@kit.AVSessionKit'; import { backgroundTaskManager } from '@kit.BackgroundTasksKit'; import { BusinessError } from '@kit.BasicServicesKit'; class BackgroundAudioPlayer { private session: AVSessionManager.AVSession | undefined = undefined; async setupBackgroundPlayback() { try { // 1. 创建媒体会话 this.session = await AVSessionManager.createAVSession( getContext(this), 'audio', 'com.example.mediaplayer' ); // 2. 激活会话 await this.session.activate(); // 3. 设置会话元数据 let metadata: AVSessionManager.AVMetadata = { assetId: '001', title: '歌曲标题', artist: '艺术家', album: '专辑名称', duration: 240000 }; await this.session.setAVMetadata(metadata); // 4. 设置播放状态 let playbackState: AVSessionManager.AVPlaybackState = { state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, speed: 1.0, position: { elapsedTime: 0, updateTime: Date.now() } }; await this.session.setAVPlaybackState(playbackState); // 5. 申请长时任务 let bgMode = backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK; backgroundTaskManager.startBackgroundRunning(getContext(this), bgMode); } catch (err) { let error = err as BusinessError; console.error(`Setup background playback failed: ${error.message}`); } } async stopBackgroundPlayback() { // 停止长时任务 backgroundTaskManager.stopBackgroundRunning(getContext(this)); // 销毁会话 if (this.session) { await this.session.deactivate(); await this.session.destroy(); } } }
八、最佳实践
8.1 性能优化
1. 资源预加载
class MediaResourceManager { private soundPool: media.SoundPool | undefined = undefined; private soundCache: Map<string, number> = new Map(); async preloadSounds(sounds: string[]) { for (let sound of sounds) { let fd = await this.getSoundFd(sound); let soundId = await this.soundPool!.load(fd.fd, fd.offset, fd.length); this.soundCache.set(sound, soundId); } } async playPreloadedSound(soundName: string) { let soundId = this.soundCache.get(soundName); if (soundId) { await this.soundPool!.play(soundId, {} as media.PlayParameters, () => {}); } } private async getSoundFd(name: string) { let context = getContext(this); return await context.resourceManager.getRawFd(name); } }
2. 内存管理
class PlayerLifecycleManager { private player: media.AVPlayer | undefined = undefined; async onPageShow() { // 页面显示时创建播放器 if (!this.player) { this.player = await media.createAVPlayer(); } } async onPageHide() { // 页面隐藏时释放播放器资源 if (this.player) { await this.player.stop(); await this.player.release(); this.player = undefined; } } }
8.2 错误处理
class RobustMediaPlayer { private avPlayer: media.AVPlayer | undefined = undefined; private retryCount: number = 0; private maxRetries: number = 3; async playWithRetry(url: string) { try { await this.play(url); this.retryCount = 0; } catch (err) { let error = err as BusinessError; console.error(`Play failed: ${error.code}`); if (this.retryCount < this.maxRetries) { this.retryCount++; console.info(`Retry ${this.retryCount}/${this.maxRetries}`); setTimeout(() => { this.playWithRetry(url); }, 1000 * this.retryCount); } else { console.error('Max retries reached'); // 通知用户播放失败 } } } private async play(url: string) { if (!this.avPlayer) { this.avPlayer = await media.createAVPlayer(); } this.avPlayer.url = url; await this.avPlayer.prepare(); await this.avPlayer.play(); } }
8.3 音频焦点管理
import { audio } from '@kit.AudioKit'; class AudioFocusManager { private avPlayer: media.AVPlayer | undefined = undefined; async setupAudioFocus() { if (!this.avPlayer) { return; } // 设置音频中断模式 this.avPlayer.audioInterruptMode = audio.InterruptMode.INDEPENDENT_MODE; // 监听音频焦点变化 this.avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => { console.info(`Audio interrupt: ${info.hintType}`); switch (info.hintType) { case audio.InterruptHint.INTERRUPT_HINT_PAUSE: // 暂停播放 this.avPlayer?.pause(); break; case audio.InterruptHint.INTERRUPT_HINT_RESUME: // 恢复播放 this.avPlayer?.play(); break; case audio.InterruptHint.INTERRUPT_HINT_STOP: // 停止播放 this.avPlayer?.stop(); break; case audio.InterruptHint.INTERRUPT_HINT_DUCK: // 降低音量 this.avPlayer?.setVolume(0.3); break; case audio.InterruptHint.INTERRUPT_HINT_UNDUCK: // 恢复音量 this.avPlayer?.setVolume(1.0); break; } }); } }
九、支持的格式
9.1 音频格式
| 格式 | 编解码器 | 封装格式 |
|---|---|---|
| AAC | AAC-LC, HE-AAC | MP4, M4A, AAC |
| MP3 | MP3 | MP3 |
| FLAC | FLAC | FLAC |
| Vorbis | Vorbis | OGG |
| Opus | Opus | OGG |
9.2 视频格式
| 格式 | 视频编解码器 | 音频编解码器 | 封装格式 |
|---|---|---|---|
| H.264 | AVC | AAC, MP3 | MP4, MKV |
| H.265 | HEVC | AAC, MP3 | MP4, MKV |
十、总结
本文全面介绍了HarmonyOS Media Kit的核心能力:
| 功能模块 | 主要API | 适用场景 |
|---|---|---|
| 音频播放 | AVPlayer | 播放完整音频文件 |
| 短音播放 | SoundPool | 低时延音效播放 |
| 视频播放 | AVPlayer | 播放视频文件 |
| 音频录制 | AudioCapturer, AVRecorder | 录制音频 |
| 视频录制 | AVRecorder + Camera | 录制视频 |
| 后台播放 | AVSession + 长时任务 | 后台音乐播放 |
开发要点:
- ✅ 根据场景选择合适的API
- ✅ 正确处理播放器状态转换
- ✅ 做好错误处理和重试机制
- ✅ 及时释放资源避免内存泄漏
- ✅ 后台播放需注册AVSession
- ✅ 正确处理音频焦点事件
通过本文学习,您应该能够:
- 熟练使用AVPlayer播放音视频
- 使用SoundPool实现低时延音效
- 实现音视频录制功能
- 开发完整的多媒体播放器应用
- 实现后台播放和媒体会话管理
更多推荐


所有评论(0)