首页 鸿蒙 正文
  • 本文约3217字,阅读需16分钟
  • 284
  • 0

鸿蒙开发封装音频播放 AVPlayer 和 申请长时任务

使用AVPlayer可以实现端到端播放原始媒体资源,本开发指导将以完整地播放一首音乐作为示例,向开发者讲解AVPlayer音频播放相关功能。如需播放PCM音频数据,请使用AudioRenderer

播放的全流程包含:创建AVPlayer,设置播放资源,设置播放参数(音量/倍速/焦点模式),播放控制(播放/暂停/跳转/停止),重置,销毁资源。

在进行应用开发的过程中,开发者可以通过AVPlayer的state属性主动获取当前状态或使用on('stateChange')方法监听状态变化。如果应用在音频播放器处于错误状态时执行操作,系统可能会抛出异常或生成其他未定义的行为。

1. 封装一个本地音频播放:

import { media } from '@kit.MediaKit';

// 封装 播放本地音频
class AVPlayerManager {
  private avPlayer: media.AVPlayer | null = null
  private loop: boolean = false
  private rawFdPath: string = ''

  async getAVPlayerInstance() {
    // 如果已存在,直接返回
    if (this.avPlayer !== null) {
      return this.avPlayer
    }
    // 初始化播放器
    const player = await media.createAVPlayer()
    player.on('stateChange', (state) => {
      switch (state) {
        case 'initialized':
          player.prepare()
          break;
        case 'prepared':
          player.play()
          break;
        case 'playing':
          player.play()
          break;
        case 'paused':
          player.pause()
          break;
        case 'completed':
          if (this.loop) {
            player.play() // 播放结束继续播放:循环播放
          } else {
            player.stop() // 播放结束
          }
          break;
        case 'stopped':
          player.reset() // stop 时 reset -> 释放音频资源
          break;
        default:
          break;
      }
    })
    this.avPlayer = player
    return this.avPlayer
  }

  // 加载 src/main/resources/rawfile 的文件
  async playByRawSrc(rawFdPath: string) {
    const player = await this.getAVPlayerInstance()
    // 先释放原来的资源
    await player.reset()
    // 获取文件信息
    const context = getContext()
    // 加载 src/main/resources/rawfile 文件夹中的文件
    const fileDescriptor = await context.resourceManager.getRawFd(rawFdPath)
    // 设置播放路径
    player.fdSrc = fileDescriptor
    // 播放
    player.play()
  }

  // 停止播放
  async stop() {
    const player = await this.getAVPlayerInstance()
    this.loop = false
    player.stop()
  }

  // 是否循环播放
  async setLoop(isLoop: boolean) {
    this.loop = isLoop
  }
}

export const avPlayerManager = new AVPlayerManager()

2. 添加本地 音频文件:

目录地址:下载声音素材文件,解压到 src/main/resources/rawfile 文件夹中。如果没有 rawfile 文件夹,请新建 rawfile 文件夹。

音频文件下载:室内守护 (yuque.com)

3. 调用播放音频:

  Button('播放本地声音')
            .onClick(() => {
              // 播放本地 rawfile 目录下的资源
              avPlayerManager.playByRawSrc('lab_alarm.wav')
              // 设置为循环播放
              avPlayerManager.setLoop(true)
            })

4. 申请长时任务(后台任务):

4.1 添加长时任务权限(module.json5):

{ // 申请长时任务(后台播放、后台下载、后台录音、后台定位)
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
      },

4.2 封装长时任务API:

import { bundleManager, wantAgent } from '@kit.AbilityKit'
import { avSession } from '@kit.AVSessionKit'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'

class BackgroundRunningManager {
  // 申请长时任务
  async startBackgroundRunning() {
    const context = getContext()
    // 重点1: 提供音频后台约束能力,音频接入AVSession后,可以进行后台音频播放
    const session = await avSession.createAVSession(context, 'guardianSession', 'audio')
    await session.activate()
    // 获取 bundle 应用信息
    const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
    // 通过wantAgent模块下getWantAgent方法获取WantAgent对象
    const wantAgentObj = await wantAgent.getWantAgent({
      // 添加需要被拉起应用的bundleName和abilityName
      wants: [{ bundleName: bundleInfo.name, abilityName: "EntryAbility" }],
      // 使用者自定义的一个私有值
      requestCode: 0,
    })
    // 重点2: 创建后台任务
    await backgroundTaskManager.startBackgroundRunning(context,
      backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj)
  }

  // 停止后台任务
  async stopBackgroundRunning() {
    backgroundTaskManager.stopBackgroundRunning(getContext())
  }
}

export const backgroundRunningManager = new BackgroundRunningManager()

4.3 使用创建后台任务:

  aboutToAppear() {
    // 播放本地 rawfile 目录下的资源
    avPlayerManager.playByRawSrc('lab_alarm.wav')
    // 设置为循环播放
    avPlayerManager.setLoop(true)
    // 申请后台人任务
    backgroundRunningManager.startBackgroundRunning()
  }

  aboutToDisappear(): void {
    avPlayerManager.stop() // 停止播放
    // 关闭后台任务
    backgroundRunningManager.stopBackgroundRunning()
  }

 

评论