开发中使用——鸿蒙播放本地mp3文件

文章目录


背景

项目中有个功能需要播放本地的mp3音频,想着只是一个简单的功能,看一下官方文档,很容易就实现了,因为苹果和安卓都很容易实现。

现实

现实是打脸的,按照官方文档------使用AVPlayer播放音频(ArkTS)文档写一遍,你会发现无论是加载网上的.mp3文件,还是本地rawfile文件下的.mp3都报错。

解决

一、创建AVPlayer实例对象

复制代码
  /**
   * 创建Player实例
   */
  async createAVPlayerInstance() {
    this.avPlayer = await media.createAVPlayer();
  }

二、设置mp3的播放路径

复制代码
  /**
   * 设置mp3的播放路径
   * @param context
   * @param path
   */
  async setSourcePath(context:common.UIAbilityContext,path: string) {
    setTimeout(async () => {
      if (this.avPlayer) {
        try {
          let fileDescriptor = await context.resourceManager.getRawFd(path);
          let fileFd: number = JSON.parse(JSON.stringify(fileDescriptor))['fd']
          let fileOffset: number = JSON.parse(JSON.stringify(fileDescriptor))['offset']
          let avFileDescriptor: media.AVFileDescriptor = { fd: fileFd, offset: fileOffset, length: -1 };
          this.avPlayer!.fdSrc = avFileDescriptor;

        } catch (err) {
          console.info('Set Url failed : ' + JSON.stringify(err))
        }
      }
    }, 500)
  }

三、设置AVPlayer回调,监听播放事件

复制代码
  /**
   * 设置avplayer回调,监听播放事件
   */
  private setAVPlayerCallback() {
    if (!this.avPlayer) {
      return
    }
    // seek操作结果回调
    this.avPlayer!.on('seekDone', (seekDoneTime) => {
      console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
    })

    // 音量变化回调
    this.avPlayer!.on('volumeChange', (volume) => {
      console.info(`volumeChange called, and new volume is :${volume}`);
    })

    // 音频总时长
    this.avPlayer!.on('durationUpdate', (duration) => {
      console.info(`durationUpdate :${duration}`);
      this.duration = duration;
    })

    // 当前播放进度
    this.avPlayer!.on('timeUpdate', (time) => {
      let now = Math.floor(time/1000)
      if (this.process != now) {
        console.info(`timeUpdate :${now}`);
      }
      this.process = now
    })

    // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程
    this.avPlayer!.on('error', (err) => {
      console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
      this.avPlayer!.reset(); // 调用reset重置资源,触发idle状态
    })

    // 状态机变化回调函数
    this.avPlayer!.on('stateChange', async (state, reason) => {
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报
          console.info('AVPlayer state idle called.');
          this.avPlayer!.release(); // 调用release接口销毁实例对象
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.info('AVPlayer state initialized called.');
          this.avPlayer!.prepare().then(() => {
            console.info('AVPlayer prepare succeeded.');
          }, () => {
            console.error(`Invoke prepare failed, code is`);
          });
          break;
        case 'prepared': // prepare调用成功后上报该状态机
          console.info('AVPlayer state prepared called.');
          this.avPlayer!.loop = this.loop
          if (this.autoPlay) {
            this.avPlayer!.play(); // 调用播放接口开始播放
          }
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.info('AVPlayer state playing called.');
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.info('AVPlayer state paused called.');
          break;
        case 'completed': // 播放结束后触发该状态机上报
          console.info('AVPlayer state completed called.');
          if (this.loop == true) {
            this.avPlayer!.seek(0)
            this.avPlayer!.play()
          }
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.info('AVPlayer state stopped called.');
          break;
        case 'released':
          console.info('AVPlayer state released called.');
          break;
        default:
          console.info('AVPlayer state unknown called.');
          break;
      }
    })
  }

四、其他操作

  • 播放

    复制代码
    /**
     * 播放
     */
    play() {
      if (!this.avPlayer) {
        this.autoPlay = true
        return
      }
    
      this.avPlayer!.play().then(() => {
        console.info('Play success')
      }).catch((err: BusinessError) => {
        console.info('Play failed : ' + JSON.stringify(err))
      })
    }
  • 暂停

    复制代码
    /**
     * 暂停
     */
    pause() {
      if (!this.avPlayer) {
        this.autoPlay = false
        return
      }
      this.avPlayer!.pause().then(() => {
        console.info('Pause success')
      }).catch((err: BusinessError) => {
        console.info('Pause failed : ' + JSON.stringify(err))
      })
    }
  • 释放资源

    复制代码
    /**
     * 释放资源
     */
    release() {
      if (!this.avPlayer) {
        this.autoPlay = false
        return
      }
      this.avPlayer!.release().then(() => {
        console.info('release success')
      }).catch((err: BusinessError) => {
        console.info('release failed : ' + JSON.stringify(err))
      })
    }

感谢

【Harmony Next】使用 AVPlayer 播放音频

吐槽

官方有时间,还是自己跑一遍文档中的代码,以及链接提供的Demo吧!请不要浪费我们开发者的时间,谢谢。
官方文档------使用AVPlayer播放音频(ArkTS)

相关推荐
猫林老师18 小时前
HarmonyOS分布式硬件共享:调用手机摄像头的手表应用
华为·交互·harmonyos
前端世界1 天前
HarmonyOS应用开发指南:Toast无法显示的完整排查流程与实战案例
华为·harmonyos
安卓开发者1 天前
鸿蒙NEXT Wear Engine穿戴侧应用开发完全指南
ubuntu·华为·harmonyos
安卓开发者1 天前
鸿蒙Next振动开发指南:打造沉浸式触觉反馈体验
华为·harmonyos
Devil枫1 天前
HarmonyOS屏幕方向适配指南
华为·harmonyos
li理1 天前
鸿蒙Image Kit深度解析:从图片解码到高级特效处理
harmonyos
li理1 天前
鸿蒙相机开发中篇:自定义 UI 与拍摄控制
harmonyos
misty youth1 天前
配置openguass 教程(自存)
数据库·ubuntu·华为·openguass
鸿蒙小白龙1 天前
OpenHarmony 与 HarmonyOS 的 NAPI 开发实战对比:自上而下与自下而上的差异解析
harmonyos·鸿蒙·鸿蒙系统·open harmony
喵手1 天前
【参赛心得】从“碰一碰”到“服务流转”:HarmonyOS创新赛金奖作品“智游文博”全流程复盘!
华为·harmonyos·鸿蒙应用开发·1024征文