【Purple Pi OH RK3566鸿蒙开发板】OpenHarmony音频播放应用,真实体验感爆棚!

本文转载于Purple Pi OH开发爱好者,作者ITMING 。

原文链接:https://bbs.elecfans.com/jishu_2376383_1_1.html

01注意事项

  • DevEco Studio 4.0 Beta2(Build Version: 4.0.0.400)

  • OpenHarmony SDK API 9

  • 创建工程类型选择Application

  • 修改entry/build-profile.json5配置文件中的targets>runtimeOS为OpenHarmony,然后进行Sync Now(同步)

0 2工程概述

PPI有声是一款基于OpenHarmony API 9 开发的,运行于Purple Pi 开发板(安装OpenHarmony标准系统)的音频播放应用程序。

0 3场景化

  • 智慧家居类(电子门铃,温湿度显示仪,屏显灯控开关等)

  • 智慧办公类(打卡机,大屏显示等)

  • 智慧教育类(电子班牌,校园大屏,电子讲台等)

0 4创建工程

  • Project name:工程名称

  • Bundle name:包名

  • Save location:工程存储路径

  • Compile SDK:编译API版本

  • Compatible SDK:兼容的最新API版本

  • Module name:模块名称

  • Model:模型

  • Enable Super Visual:是否启用低代码开发

  • Device Type:设备类型

  • Node:nodejs路径

0 5媒体服务

媒体子系统为开发者提供一套简单且易于理解的接口,使得开发者能够方便接入系统使用系统的媒体资源。

媒体子系统包含了音视频相关媒体业务,提供以下常用共功能:

  • 音视频播放(AVPlayer)

  • 音视频录制(AVRecorder)

    5.1 AVPlayer概述

AVPlayer主要工作是将Audio/Video媒体资源(比如mp4/mp3/mkv/mpeg-ts等)转码为可供渲染的图像或可听见的模拟信号,并通过输出设备进行播放。

使用AVPlayer可以实现端到端播放原始媒体资源,播放对的全流程包含:创建AVPlayer,设置播放资源,设置播放参数 (音量/倍速/焦点模式),播放控制(播放/暂停/跳转/停止),重置,销毁资源。

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

主:当播放处于prepared/playing/paused/completed状态时,播放引擎处于工作状态,需要占用系统较多的运行内容。当客户端暂时不适用播放器时,调用reset()或release()回收内存资源。

5.2 开发步骤

  1. 导入media模块,调用createAVPlayer()方法创建AVPlayer实例,AVPlayer初始化idle状态。

  2. 设置业务监听事件,搭配全流程场景使用,如监听播放器state属性改变的stateChange;监听播放器错误信息的error;用于进度条,监听进度条长度,刷新资源时长的durationUpdate等。

  3. 设置资源:设置属性url,AVPlayer进入initialized状态

  4. 准备播放:调用prepare(),AVPlayer进入prepared状态,此时可以获取duration,设置音量。

  5. 音频播控:播放play(),暂停pause(),跳转seek(),停止stop()等操作。

  6. 调用reset()重置资源,AVPlayer重新进入idle状态,此时可更换播放源url。

  7. 调用release()销毁实例,AVPlayer进入released状态,退出播放。

0 6构建PPI有声

6.1 准备资源文件

  • 音频文件拷贝到resources/rawfile目录

  • 将拷贝到resources/base/mdiea目录

  • 音频播放背景图audio_bg.png

  • 音频播放旋转图audio.png

  • 暂停ic_pause.svg

  • 播放ic_play.svg

6.2 构建UI页面

整个UI以Flex弹性布局为主,子组件以列方式排列,分别为可旋转的音频播放控件,播放进度条以及播放控制按钮组成。

6.2.1 可旋转的音频播放控件

使用Stack堆叠布局容器为主,将旋转控件置于背景图之上。

复制代码
Stack({ alignContent: Alignment.Center }) {
        Image($r('app.media.audio_bg'))
          .width(200).height(200)
        Image($r('app.media.audio'))
          .width(100).height(100)
          .backgroundColor(Color.White)
          .borderRadius(50)
          .rotate({ angle: this.angleNum })
          .animation({
            duration: this.duration,
            tempo: 1,
            curve: Curve.Linear,
            iterations: -1,
            playMode: PlayMode.Normal
          })
      }
复制代码
6.2.2 进度条

播放进度由置于上部的播放时长和总时长,底部的播放进度条组成,包裹在Column列容器中。

复制代码
Column({ space: 4 }) {
        Row() {
          Text(this.msToS(this.currentProgress))
            .fontSize(12)
            .fontColor(0xc1c3c5)
          Text(this.msToS(this.duration))
            .fontSize(12)
            .fontColor(0xc1c3c5)
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        // 播放进度条
        Slider({
          value: this.currentProgress,
          min: 0,
          max: this.duration,
          style: SliderStyle.OutSet
        })
          .showTips(true)
          .onChange((value: number, mode: SliderChangeMode) => {
            this.currentProgress = value;
            // 跳转到指定位置播放
            this.avPlayer.seek(value);
          })
      }
      .width('90%')
复制代码

6.2.3 播放控件

播放控件通过当前AVPlayer的状态判断显示播放/暂停图标按钮。

复制代码
Row({ space: 10 }) {
        if (this.state === 'playing') {
          // 暂停
          Image($r('app.media.ic_pause'))
            .width(64).height(64)
            .fillColor(0xff5722)
            .onClick(() => {
              // 暂停播放
              this.avPlayer.pause().then(() => {
                this.angleNum = 0;
              })
            })
        } else {
          // 播放
          Image($r('app.media.ic_play'))
            .width(64).height(64)
            .fillColor(0x00aaee)
            .onClick(async () => {
              if (this.avPlayer && this.avPlayer.state === "paused") {
                this.avPlayer.play().then(() => {
                  this.angleNum = 360;
                })
              } else {
                await this.initAVPlayer();
              }
            })
        }
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)

6.3 实现音频播放

6.3.1 初始化AVPlayer

复制代码
// 播放音频AVPlayer实例
  private avPlayer: media.AVPlayer = undefined;

  // 初始化AVPlayer
  async initAVPlayer() {
    // 创建AVPlayer实例对象
    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数
    this.setAVPlayerCallback();

    await this.loadingResourceFile();
  }
复制代码
6.3.2 加载HAP包资源文件
复制代码
// 加载HAP包资源文件
  loadingResourceFile = async () => {
    // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
    let context = getContext(this) as common.UIAbilityContext;
    let fileDir = await context.resourceManager.getRawFd("audio.wav");
    // 为fdSrc赋值触发initialized状态机上报
    this.avPlayer.fdSrc = fileDir;
  }
复制代码
6.3.3 注册AVPlayer回调函数
复制代码
// 注册AVPlayer回调函数
  setAVPlayerCallback = () => {
    // 状态机变化回调函数
    // state:表示当前播放状态
    // reason:表示当前播放状态的切换原因
    this.avPlayer.on('stateChange', async (state, reason) => {
      this.state = this.avPlayer.state;
      switch (state) {
        case 'initialized':
          this.avPlayer.prepare().then(() => {
            // 音频播放准备完毕后,获取音频总时长
            this.duration = this.avPlayer.duration;
          })
          break;
        case 'prepared':
          // 开始播放
          this.avPlayer.play().then(() => {
            // 设置图标开始旋转
            this.angleNum = 360;
          })
          break;
      }
    })

    // 播放错误回调函数
    this.avPlayer.on('error', (err) => {
      console.error(`Error happened. Cause: ${JSON.stringify(err)}`);
    })
    // 监听资源播放当前时间回调函数
    this.avPlayer.on('timeUpdate', (time: number) => {
      if (this.avPlayer.state === 'completed') {
        this.currentProgress = 0;
        this.duration = 0;
        this.angleNum = 0;
      } else {
        this.currentProgress = time;
      }
    })
  }
复制代码
07效果预览
相关推荐
一起搞IT吧4 小时前
嵌入式ARM SOC开发中文专题分享一:ARM SOC外围资源介绍
arm开发·嵌入式硬件
研华嵌入式5 小时前
如何在高通跃龙QCS6490 Arm架构上使用Windows 11 IoT企业版?
arm开发·windows·嵌入式硬件
低调小一5 小时前
Android传统开发 vs Android Compose vs HarmonyOS ArkUI 对照表
android·华为·harmonyos
矢志不移7925 小时前
裸机开发 时钟配置,EPIT
单片机·嵌入式硬件
清风6666666 小时前
基于STM32的APP遥控视频水泵小车设计
stm32·单片机·mongodb·毕业设计·音视频·课程设计
Cary丿Xin7 小时前
Luma 视频生成 API 对接说明
音视频
程序员江同学7 小时前
ovCompose + AI 开发跨三端的 Now in Kotlin App
android·kotlin·harmonyos
猛码Memmat9 小时前
华为HarmonyOS开发文档
华为·harmonyos
物随心转9 小时前
RTC驱动原理
嵌入式硬件