头图

【高心星出品】

音频播放组件的封装

鸿蒙中提供了AVPlayer来实现音频播放的功能,播放的全流程包含:创建AVPlayer,设置播放资源,设置播放参数(音量/倍速/焦点模式),播放控制(播放/暂停/跳转/停止),重置,销毁资源。在进行应用开发的过程中,开发者可以通过AVPlayer的state属性主动获取当前状态或使用on('stateChange')方法监听状态变化。如果应用在音频播放器处于错误状态时执行操作,系统可能会抛出异常或生成其他未定义的行为。

AVPlayer的状态机变化图:

在这里插入图片描述

开发步骤

  1. 创建实例createAVPlayer(),AVPlayer初始化idle状态。
  2. 设置业务需要的监听事件,搭配全流程场景使用。
  3. 设置资源:设置属性url,AVPlayer进入initialized状态。
  4. 准备播放:调用prepare(),AVPlayer进入prepared状态,此时可以获取duration,设置音量。
  5. 音频播控:播放play(),暂停pause(),跳转seek(),停止stop() 等操作。
  6. (可选)更换资源:调用reset()重置资源,AVPlayer重新进入idle状态,允许更换资源url。
  7. 退出播放:调用release()销毁实例,AVPlayer进入released状态,退出播放。

但是AVPlayer用起来太麻烦,下面我做一个简单的封装。

封装类代码

/**
 *作者:gxx
 *时间:2024/11/1 14:32
 *功能:
 **/
import { media } from "@kit.MediaKit";
import { BusinessError } from "@kit.BasicServicesKit";
import { promptAction } from "@kit.ArkUI";

export class MediaPlayer {
  private player: media.AVPlayer
  private source: media.AVFileDescriptor | string
  private state: media.AVPlayerState = 'idle'

  constructor(player: media.AVPlayer, source: media.AVFileDescriptor | string) {
    // 创建出来player
    this.player = player;
    // 设置监听
    this.setListener()
    this.source = source;
    // 设置播放资源
    if (typeof source == 'string') {
      this.player.url = source
    } else {
      this.player.fdSrc = source
    }
  }

  // 设置监听
  private setListener() {
    // 播放错误
    this.player.on('error', (err: BusinessError) => {
      console.error('gxxt play err: ', err.message)
    })
    // 播放完毕
    this.player.on("endOfStream", () => {
      console.log('gxxt play 完毕')
    })
    this.player.on("stateChange", (state, reason) => {
      // 更新当前状态
      this.state = state
      switch (state) {
        case 'idle':
          console.log('gxxt play 刚创建')
          break;
        case 'initialized':
          console.log('gxxt play 初始化好了播放资源')
          this.player.prepare()
          break;
        case 'prepared':
          console.log('gxxt  play 准备好的状态')
          break;
        case 'playing':
          console.log('gxxt play 播放中状态')
          break;
        case 'paused':
          console.log('gxxt play 暂停的状态')
          break;
        case 'stopped':
          console.log('gxxt play 停止的状态')
          break;
        case 'released':
          console.log('gxxt play 释放资源')
          break;
      }
    })
  }

  play() {
    // 如果当前状态是准备态或者暂停可以直接播放  否则先准备
    if (this.state == 'prepared' || this.state == 'paused') {
      this.player.play()
    } else if (this.state == 'stopped') {
      this.player.prepare(() => {
        // 停止状态进来的 要先准备 再开始播放
        this.player.play()
      })
    }
  }

  pause() {
    // 只有是播放状态才能暂停
    if (this.state == 'playing') {
      this.player.pause()
    } else {
      promptAction.showToast({ message: '当前状态不支持暂停' })
    }
  }
  // 停止播放
  stop() {
    this.player.stop()
  }
  //释放资源
  release() {
    this.player.release()
  }

  seekto(time: number) {
    // 滑动播放时间
    if (time < this.player.duration) {
      this.player.seek(time)
    }
  }
}

测试代码

创建AVPplayer对象并准备播放资源。

async aboutToAppear(): Promise<void> {
  //   创建播放器
  let avplayer = await media.createAVPlayer()
  // 获取test.mp3的文件描述符
  let filedes = getContext(this).resourceManager.getRawFdSync('test.mp3')
  // 创建播放资源
  let source: media.AVFileDescriptor = { offset: filedes.offset, fd: filedes.fd, length: filedes.length }
  this.player = new MediaPlayer(avplayer, source)
}
aboutToDisappear(): void {
  this.player?.release()
  }

通过按钮来控制音频的播放和暂停。

Button('播放')
  .width('60%')
  .margin(20)
  .onClick(() => {
    this.player?.play()
  })
Button('暂停')
  .width('60%')
  .margin(20)
  .onClick(() => {
   this.player?.pause()
  })
Button('停止')
  .width('60%')
  .margin(20)
  .onClick(() => {
  this.player?.stop()
  })

在这里插入图片描述


高心星
1 声望1 粉丝

华为开发者专家(HDE)。 10年教学经验,兼任多家科技公司技术顾问。先后从事JavaEE项目开发、Python爬虫、HarmonyOS移动应用开发等课程的教学工作。参与开发《鸿蒙应用开发基础》和《鸿蒙项目实战》等课程。