#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器 原创

带带带师
发布于 2024-7-31 00:51
浏览
2收藏

自我踏上鸿蒙系统学习之旅以来,已历经一段时光。这次也是有幸能够体验鸿蒙系统next版本,那么就看看在新的环境下能做什么吧。
我依稀记得初次尝试构建的一个基于Video组件的视频播放器的小demo。在那个demo中,实现基本的视频播放只需要Video组件就可以完成。那么既然有了视频播放,音乐播放该怎么实现呢?

诶,有Video组件,应该也有Music组件吧。

#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区

其实,鸿蒙提供了不止一种能够播放音乐的途径,就比如在文档中有的一个Audio Kit音频服务,还有Media kit媒体服务,那这次的小demo我就利用了Media中的avplayer来完成。

Media Kit介绍

Media Kit(媒体服务)提供了音视频的播放,录制开发方式,我们可以调用音视频的API实现相应的功能。

AVPlayer

AVPlayer主要工作是将Audio/Video媒体资源(比如mp4/mp3/mkv/mpeg-ts等)转码为可供渲染的图像和可听见的音频模拟信号,并通过输出设备进行播放。AVPlayer提供功能完善一体化播放能力,应用只需要提供流媒体来源,不负责数据解析和解码就可达成播放效果。

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

在此demo中实现音乐的播放,暂停与切换就是利用AVPlayer实现的。

开发流程

  • 在定义avplayer时,我们需要注意其初始化过程,以确保代码的合规性。同时,鉴于avplayer在使用过程中有可能出现null的情况,为了避免编译器报错和潜在的逻辑错误,我们在编写代码时还需加入对avplayer状态的检查机制。(当时我在写的时候就是因为这个卡了一下,大家也要注意。)
private avPlayer: media.AVPlayer|null=null;

#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区

  • 接下来简要介绍页面布局方面。我们运用了三个容器来划分界面,使主要的音乐列表(list)占据视觉中心,同时在列表下方增设了一个控制播放暂停的按钮(button),在这里实现音乐的暂停播放。

  • 为了实现音乐的播放功能,我们在列表项(list)中集成了点击事件。当用户点击列表中的某一音乐时,通过资源管理器接口获取对应的媒体文件,并利用avplayerfdSrc属性进行播放。我们在点击事件中首先创建一个avplayer的实例(若尚未存在),随后调用reset()方法以切换播放资源,从而确保在播放新音乐的同时能够结束上一首音乐的播放,避免了音乐重叠播放的混乱情况。

  async onPageShow() {
    // 创建avPlayer实例对象
    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数
    this.setAVPlayerCallback();
    console.info('播放器准备完成')
  }

  // 以下为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放
  async avPlayerchange(item:number) {
    if (this.avPlayer !== null) {
      this.avPlayer?.reset()
      // 创建状态机变化回调函数
      this.setAVPlayerCallback();
      // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
      // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
      let context = getContext(this) as common.UIAbilityContext;
      let fileDescriptor = await context.resourceManager.getRawFd(this.res[item]);
      // 为fdSrc赋值触发initialized状态机上报
      this.avPlayer.fdSrc = fileDescriptor;
      // this.isSeek = false; // 不支持seek操作
    }
  }
  • 对于音乐的暂停与恢复播放功能,我们同样依赖于avplayer提供的pause()play()方法,通过调用这两个方法,实现了对音频播放状态的控制。
Button({ type: ButtonType.Normal, stateEffect: true }){
  Text(this.BFstate)
    .fontSize(20).fontColor(Color.White)
}.borderRadius(8).height(26).width(70).backgroundColor(Color.Orange)
.onClick(()=>{
  if (this.avPlayer !== null && this.isBFplaying==true) {
    this.avPlayer.pause()
    this.BFstate='继续'
    this.isBFplaying=false
  }else{
    this.avPlayer?.play()
    this.BFstate='暂停'
    this.isBFplaying=true
  }
})
画面分配 布局 最终效果
#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区 #HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区 #HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区

功能

  1. 点击列表中的音乐开始播放
  2. 点击暂停按钮暂停音乐
  3. 音乐暂停后点击播放按钮继续播放

实现效果

没有声音见谅,大家可以自己把代码复制下来,修改一下就可以播放自己想要的音乐了

#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区

代码

import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';

@Entry
@Component
struct Index {
  private avPlayer: media.AVPlayer|null=null;

  async onPageShow() {
    // 创建avPlayer实例对象
    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数
    this.setAVPlayerCallback();
    console.info('播放器准备完成')
  }
  private arr: number[] = [0, 1, 2, 3, 4]
  @State titlenumber:number=-1
  @State isBFplaying:Boolean=true
  @State BFstate:string='暂停'
  @State title: string[] = ['花日', '踊り子', 'Fukashigi no Carte','snooze', "It's Going Down Now"]
  @State zuozhe: string[] = ['CMJ','Vaundy','Halcyon','wotaku','P3']
  //资源放在resources目录下的rawfile文件夹中
  @State res:string[]=['CMJ.mp3','Vaundy.mp3','Halcyon.mp3','wotaku.mp3','P3.mp3']
  build() {
    Column(){
      Row(){
        Row(){
          Text('我的音乐')
            .fontColor(Color.White).fontSize(32)
        }.margin({left:20})
      }.backgroundColor(Color.Gray).height('8%').width('100%')
      Column(){
        List(){
          ForEach(this.arr,(item:number)=>{
            ListItem(){
              Row(){
                Button({type:ButtonType.Normal}){
                  Row(){
                    Text((item+1)+'  ')
                      .fontSize(32)
                    Column(){
                      Text(this.title[item]).fontSize(20).fontWeight(700)
                      Text(this.zuozhe[item]).fontSize(14)
                    }.alignItems(HorizontalAlign.Start)
                  }.justifyContent(FlexAlign.Start)
                  .width('90%')
                }
                .backgroundColor(Color.White)
                .width("100%").height(50)
                .margin({top:10})
                .onClick(()=>{
                  this.BFstate='暂停'
                  this.isBFplaying=true
                  this.titlenumber=this.arr[item]
                  this.onPageShow()
                  this.avPlayerchange(item);
                })
              }
            }
          })
        }.width('100%')
      }.height('84%')
      Row(){
        Row(){
          if (this.titlenumber==-1){
            Text('点击歌曲开始播放')
              .fontSize(20).fontColor(Color.White)
          }else {
            Column(){
              Text(this.title[this.titlenumber])
                .fontSize(20).fontColor(Color.White)
            }.width('70%').alignItems(HorizontalAlign.Start)
            Column(){
              Button({ type: ButtonType.Normal, stateEffect: true }){
                Text(this.BFstate)
                  .fontSize(20).fontColor(Color.White)
              }.borderRadius(8).height(26).width(70).backgroundColor(Color.Orange)
              .onClick(()=>{
                if (this.avPlayer !== null && this.isBFplaying==true) {
                  this.avPlayer.pause()
                  this.BFstate='继续'
                  this.isBFplaying=false
                }else{
                  this.avPlayer?.play()
                  this.BFstate='暂停'
                  this.isBFplaying=true
                }
              })
            }.width('20%')
          }
        }.width('99%').margin({left:15})
      }.backgroundColor(Color.Gray).height('8%').width('100%')
    }.height('100%').width('100%')
  }

  // 以下为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放
  async avPlayerchange(item:number) {
    if (this.avPlayer !== null) {
      this.avPlayer?.reset()
      // 创建状态机变化回调函数
      this.setAVPlayerCallback();
      // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
      // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
      let context = getContext(this) as common.UIAbilityContext;
      let fileDescriptor = await context.resourceManager.getRawFd(this.res[item]);
      // 为fdSrc赋值触发initialized状态机上报
      this.avPlayer.fdSrc = fileDescriptor;
      // this.isSeek = false; // 不支持seek操作
    }
  }

  setAVPlayerCallback() {
    if (this.avPlayer !== null) {
      this.avPlayer.on('error', (err) => {
        console.error(`播放器发生错误,错误码:${err.code}, 错误信息:${err.message}`);
        this.avPlayer?.reset();
      });

      this.avPlayer.on('stateChange', async (state, reason) => {
        switch (state) {
          case 'initialized':
            console.info('资源初始化完成');
            this.avPlayer?.prepare();
            break;
          case 'prepared':
            console.info('资源准备完成');
            this.avPlayer?.play();
            break;
          case 'completed':
            console.info('播放完成');
            this.avPlayer?.stop();
            break;
        }
      });
    }
  }
}

在鸿蒙的学习路上,我算是刚刚踏上征途的新手。如果大家对我的demo感兴趣,也欢迎大家自己去尝试一下。如果代码中有什么问题,也恳请大佬指正。

谢谢各位。(鼓掌鼓掌)

#HarmonyOS NEXT体验官#利用Media Kit实现音乐播放器-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2024-7-31 00:51:01修改
6
收藏 2
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

从发布时间直观感受和大佬的差距


回复
2024-7-31 10:46:09
wx658826fe0fb88
wx658826fe0fb88

博主太厉害了😭😭

回复
2024-7-31 12:03:58
第一小趴菜
第一小趴菜

陈桑6


回复
2024-7-31 12:14:57
回复
    相关推荐