【Purple Pi OH RK3566 Harmony开发板】OpenHarmony音频播放应用

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(同步)
02工程概述
ppi有声是一款基于openharmony api 9 开发的,运行于purple pi 开发板(安装openharmony标准系统)的音频播放应用程序。
03场景化
智慧家居类(电子门铃,温湿度显示仪,屏显灯控开关等)
智慧办公类(打卡机,大屏显示等)
智慧教育类(电子班牌,校园大屏,电子讲台等)
04创建工程
project name:工程名称
bundle name:包名
save location:工程存储路径
compile sdk:编译api版本
compatible sdk:兼容的最新api版本
module name:模块名称
model:模型
enable super visual:是否启用低代码开发
device type:设备类型
node:nodejs路径
05媒体服务
媒体子系统为开发者提供一套简单且易于理解的接口,使得开发者能够方便接入系统使用系统的媒体资源。
媒体子系统包含了音视频相关媒体业务,提供以下常用共功能:
音视频播放(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 开发步骤导入media模块,调用createavplayer()方法创建avplayer实例,avplayer初始化idle状态。
设置业务监听事件,搭配全流程场景使用,如监听播放器state属性改变的statechange;监听播放器错误信息的error;用于进度条,监听进度条长度,刷新资源时长的durationupdate等。
设置资源:设置属性url,avplayer进入initialized状态
准备播放:调用prepare(),avplayer进入prepared状态,此时可以获取duration,设置音量。
音频播控:播放play(),暂停pause(),跳转seek(),停止stop()等操作。
调用reset()重置资源,avplayer重新进入idle状态,此时可更换播放源url。
调用release()销毁实例,avplayer进入released状态,退出播放。
06构建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效果预览

需要了解Linux的硬链接与软链接
数控机床机械手的主要组成部分
R型试验变压器有什么特点?
介绍信号完整性的另一个要素—芯片
什么是嵌入式操作系统,它由哪些组件构成
【Purple Pi OH RK3566 Harmony开发板】OpenHarmony音频播放应用
为什么锡膏使用前一定要搅拌回温?
电子分频前后级放大器后级部分(三)
现代高层正纠结是否为苹果代工汽车
作为一名程序员到底有多难
VR安全体验馆是什么,它应用了哪些技术
带您走进“330型航空时钟”!
低代码会使初级码农失业吗
将石墨烯转化为最薄的金刚石薄膜,可实现增强电子器件的韧性
现代新胜达预计明年3月正式上市 内外设计上有了颠覆性的改变
微波雷达传感器模块,人体雷达感知存在,场景智能联动
3D扫描仪手持云台测评:手机可替代电脑采集数据
华为G9青春版:华为16年最高性价比手机,跳水50%售价899值得买了
mcgs优点有哪些
USB 3.0接口定义及封装介绍