AudioPlayerManager 音视频单例播放管理类操作文档附加案例

AudioPlayerManager 音视频单例播放管理类操作文档附加案例

https://ohpm.openharmony.cn/#/cn/detail/@zyl%2Faudio_player_manager

一、概述

AudioPlayerManager 是鸿蒙 ArkTS 平台的音频播放单例管理类,基于鸿蒙 AVPlayer 封装,提供全局统一的音视频播放能力,支持多数据源适配与完整播放控制,保障播放资源安全与状态稳定。

核心特性

  • 全局单例:避免多播放器实例冲突,统一管理播放资源

  • 多源适配:支持 URL(网络/本地)、FD 句柄(fdSrc)两种播放方式

  • 完整控制:播放/暂停/停止/跳转/倍速/音量调节全功能覆盖

  • 智能处理:自动监听状态流转、音频打断,异常时自动重置与资源回收

  • 错误兜底:完善的异常捕获机制,提供明确错误反馈

二、快速上手

2.1 导入单例实例🌞

复制代码
  ohpm install @zyl/audio_player_manager

2.2 基础播放示例

2.2.1 简单播放场景(推荐)

支持网络音频 URL 或本地沙箱文件路径

AudioPlayerManager.playAudioUrlOrFdSrc() 简单场景播放,可以传地址或者本地raw音频,

自动识别播放单独使用可以使用playByUrl和playByFdSrc进行播放

  • @param url: string|media.AVFileDescriptor
  • @param speed?: number 设置倍速
typescript 复制代码
// 1. 播放网络音频
          AudioPlayerManager.playAudioUrlOrFdSrc('https://vol.bczcdn.com/r/sa_103_6828_0_3_20150809024934.aac')
            .then(() => console.log('播放成功/完成'))
            .catch(() => console.log('播放失败或者被打断:'))

// 2. 播放本地沙箱音频(file:// 协议)
          const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
          let resource = context.resourceManager
          const value: resourceManager.RawFileDescriptor = await resource.getRawFd('mp3/error.mp3') // 资源存在 entry\src\main\resources\rawfile\mp3\error.mp3
          AudioPlayerManager.playAudioUrlOrFdSrc(value)
            .then(() => console.log('播放成功/完成'))
            .catch(() => console.log('播放失败或者被打断:'))
    

三、核心功能操作

3.1 播放控制

功能 代码示例 说明
开始播放 AudioPlayerManager.play(); 仅在 PREPARED/PAUSED 状态有效
暂停播放 AudioPlayerManager.pause(); 仅在 PLAYING 状态有效
停止播放 AudioPlayerManager.stop(); 仅在 PLAYING/PAUSED/PREPARED 状态有效,停止后可重新准备播放
销毁播放器 AudioPlayerManager.destroy(); 释放所有资源,实例不可复用,需重新获取单例
重置播放器 AudioPlayerManager.reset(); 回到 IDLE 状态,可重新设置数据源播放

3.2 进度与倍速调节

功能 代码示例 说明
进度跳转 AudioPlayerManager.seekTo(10000); 跳转至 10 秒位置(单位:毫秒),默认 SEEK_PREV_SYNC 模式;支持自定义模式(如 media.SeekMode.SEEK_NEXT_SYNC)
设置倍速 AudioPlayerManager.setSpeed(1.5); 倍速范围 0.5~2.0,仅在 PREPARED/PLAYING/PAUSED/COMPLETED 状态有效

3.3 音量调节

typescript 复制代码
// 设置音量为 50%(有效值:0.0~1.0,0 静音,1 最大音量)
AudioPlayerManager.setVolume(0.5);
    

3.4 视频播放补充(设置渲染Surface)

播放视频时需设置渲染 SurfaceId(仅在 INITIALIZED 状态有效):

typescript 复制代码
// 从视频组件获取 SurfaceId 后设置
const surfaceId = "xxx"; // 实际值从 UI 组件获取
AudioPlayerManager.setSurfaceId(surfaceId);
    

四、状态与信息查询

查询项 代码示例 返回值说明
当前播放状态 const state = AudioPlayerManager.getCurrentState; 状态枚举:IDLE/INITIALIZED/PREPARED/PLAYING/PAUSED/COMPLETED/STOPPED/RELEASED/ERROR
总时长 const total = AudioPlayerManager.duration; 音频总时长(单位:毫秒),未准备完成时返回 0
当前进度 const current = AudioPlayerManager.currentTime; 当前播放位置(单位:毫秒)
当前数据源 const source = AudioPlayerManager.getCurrentSource(); 返回当前数据源信息(type/url/fdSrc)(返回副本)
当前实例 const source = AudioPlayerManager.getAvPlayer(); 返回当前音频
当前实例,没有就创建 const source = await AudioPlayerManager.createOrGetAvPlayer(); 返回当前音频,没有就创建

五、回调监听配置

通过绑定回调函数,监听播放状态、进度、错误等事件,实现业务联动:

typescript 复制代码
  AudioPlayerManager.playByUrl('https://vol.bczcdn.com/r/sa_103_6828_0_3_20150809024934.aac').then(() => {
  AudioPlayerManager.callbacks = {
    // 状态变化回调
    onStateChange: (state, reason) => {
      console.log(`状态变更:${state},原因:${reason}`);
      if (state === "COMPLETED") {
        console.log("播放完成,可执行下一曲逻辑");
      }
    },
    // 进度更新回调(实时触发)
    onTimeUpdate: (currentTime, totalDuration) => {
      console.log(`进度:${currentTime}/${totalDuration}ms`);
    },
    // 错误回调
    onError: (error) => {
      console.error(`播放错误:错误码=${error.code},描述=${error.message}`);
    },
    // 播放完成回调
    onComplete: () => {
      console.log("音频播放完成");
    },
    // 音频被打断回调(如闹钟、来电),如果不设置,默认就是下面的代码打断
    onAudioInterrupt: (info) => {
      console.log("音频打断信息:", info);
      // 强制打断(系统强制执行,如闹钟),自动停止播放
      if (info.forceType === 0) {
        AudioPlayerManager.stop();
      }
    },
    // 新播放地址打断当前播放回调
    onResetUrl: () => {
      console.log("当前播放被新地址打断");
    }
  };
})

六、完整案例演示(AudioDemo)

以下是基于 AudioPlayerManager 开发的完整 UI 演示案例,包含 URL 播放、rawfile 本地资源播放、回调自定义、直播设置及视频播放等场景,可直接在鸿蒙应用中复用。

6.1 案例代码(音频播放)

ts 复制代码
import { AudioPlayerManager, AVPlayerState } from "../Index";
import { MyLog } from "../src/main/ets/utils/MyLog";
import { audio } from "@kit.AudioKit";
import { http } from "@kit.NetworkKit";
import { BusinessError } from "@kit.BasicServicesKit"
import { resourceManager } from "@kit.LocalizationKit";
import { common } from "@kit.AbilityKit";
import { media } from "@kit.MediaKit";
import { HashMap } from "@kit.ArkTS";
import { VideoView } from "./VideoView";

@Component
export struct AudioDemo {
  @State isShowLoading2: boolean = false

  build() {
    Scroll() {
      Column(){
        // 播放按钮
        Button('1.播放简单使用-播放在线地址或者本地地址').onClick(() => {
          // URL 快捷播放
          // 带倍速的 URL 播放
          AudioPlayerManager.playAudioUrlOrFdSrc('https://vol.bczcdn.com/r/sa_103_6828_0_3_20150809024934.aac')
            .then(() => console.log('播放成功/完成'))
            .catch(() => console.log('播放失败或者被打断:'))
        })

        Button('2.播放简单使用-播放本地的rawfile文件').onClick(async () => {
          // URL 快捷播放
          // 带倍速的 URL 播放
          const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
          let resource = context.resourceManager
          const value: resourceManager.RawFileDescriptor = await resource.getRawFd('mp3/error.mp3') // 存在 entry\src\main\resources\rawfile\mp3\error.mp3
          AudioPlayerManager.playAudioUrlOrFdSrc(value)
            .then(() => console.log('播放成功/完成'))
            .catch(() => console.log('播放失败或者被打断:'))
        })

        Button('2.播放自定义使用回调').onClick(() => {
          AudioPlayerManager.playByUrl('https://vol.bczcdn.com/r/sa_103_6828_0_3_20150809024934.aac').then(() => {
            // console.log('AudioPlayerManagement-播放完了哈')
            // 带倍速的 URL 播放
            AudioPlayerManager.callbacks = {
              onStateChange: (state: AVPlayerState) => {
                // 状态变化回调
                MyLog.log('状态变化回调-onStateChange', state)
                if (state == 'idle') {
                  // 默认值就是idle,这儿只会在状态变化时候触发
                } else if (state == 'prepared') { // AudioPlayerManager.setSpeed(1) // 设置速度
                } else if (state == 'playing') {
                } else if (state == 'paused') {
                } else if (state == 'stopped') {
                } else if (state == 'released') {
                } else if (state == 'error') {
                }
              },
              onTimeUpdate: (time) => {
                // 进度更新回调
                MyLog.log('onTimeUpdate-进度更新回调'+time)
              },
              onComplete: () => {
                // 播放完毕
                MyLog.log('onComplete-播放完毕')
              },
              onResetUrl: () => {
                // 当上个视频没播放完毕,就播放下一个视频会被打断,就执行这里
              },
              onAudioInterrupt: (info) => {
                // 不写也是打断,写了就自定义咯
                MyLog.log('1AudioPlayerManagement-onAudioInterrupt', JSON.stringify(info))
                // 被系统声音打断了,比如闹钟
                if (info.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
                  // 强制打断类型,即具体操作已由系统强制执行。
                  AudioPlayerManager.stop()
                  // hintType
                }
                // eventType   音频中断事件类型,开始或是结束。
                //INTERRUPT_TYPE_BEGIN ---1------音频播放中断事件开始。
                // INTERRUPT_TYPE_END  ---2-----音频播放中断事件结束。
                // forceType    操作是由系统强制执行或是由应用程序执行。
                // INTERRUPT_FORCE	0	强制打断类型,即具体操作已由系统强制执行。
                // INTERRUPT_SHARE	1	共享打断类型,即系统不执行具体操作,通过InterruptHint建议并提示应用操作,应用可自行决策下一步处理方式。
                // hintType     中断提示,用于提供中断事件的相关信息。
                // INTERRUPT_HINT_NONE	0  无提示。 元服务API: 从API version 12开始,该接口支持在元服务中使用。
                // INTERRUPT_HINT_RESUME	1   提示音频恢复,应用可主动触发开始渲染或开始采集的相关操作。  此操作无法由系统强制执行,其对应的InterruptForceType一定为INTERRUPT_SHARE类型。

              }
            }
          })
        })



        Button('播放自定义使用回调播放本地的rawfile文件').onClick(async () => {
          // URL 快捷播放
          // 带倍速的 URL 播放
          //播放 entry\src\main\resources\rawfile下面的音频文件mp3/error.mp3
       try {

         // 2. 第二步:构建 AVDataSrcDescriptor(定义播放规则)
         // let dataSrc: media.AVDataSrcDescriptor = {
         //   fileSize: -1, // 媒体文件总大小(字节)
         //   callback: (buffer: ArrayBuffer, len: number, pos: number) => {
         //     // - 返回值,number类型,返回填充数据的长度。返回-1表示到达流的末尾,返回-2表示遇到不可恢复的错误。
         //   }
         // };
         // AudioPlayerManager.setDataSrc(dataSrcDescriptor)

         const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
         let resource = context.resourceManager
         const value: resourceManager.RawFileDescriptor = await resource.getRawFd('mp3/error.mp3') // 存在 entry\src\main\resources\rawfile\mp3\error.mp3
         AudioPlayerManager.playByFdSrc(value).then(() => {
           // console.log('AudioPlayerManagement-播放完了哈')
           AudioPlayerManager.callbacks = {
             onStateChange: (state: AVPlayerState) => {
               // 状态变化回调
               MyLog.log('状态变化回调-onStateChange', state)
               if (state == 'idle') {
               } else if (state == 'prepared') { // AudioPlayerManager.setSpeed(1) // 设置速度
               } else if (state == 'playing') {
               } else if (state == 'paused') {
               } else if (state == 'stopped') {
               } else if (state == 'released') {
               } else if (state == 'error') {
               }
             },
             onTimeUpdate: (time) => {
               // 进度更新回调
               MyLog.log('onTimeUpdate-进度更新回调'+time)
             },
             onComplete: () => {
               // 播放完毕
               MyLog.log('onComplete-播放完毕')
             },
             onResetUrl: () => {
               // 当上个视频没播放完毕,就播放下一个视频会被打断,就执行这里
             },
             onAudioInterrupt: (info) => {
               MyLog.log('1AudioPlayerManagement-onAudioInterrupt', JSON.stringify(info))
               // 被系统声音打断了,比如闹钟
               if (info.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
                 // 强制打断类型,即具体操作已由系统强制执行。
                 AudioPlayerManager.stop()
                 // hintType
               }
               // eventType   音频中断事件类型,开始或是结束。
               //INTERRUPT_TYPE_BEGIN ---1------音频播放中断事件开始。
               // INTERRUPT_TYPE_END  ---2-----音频播放中断事件结束。
               // forceType    操作是由系统强制执行或是由应用程序执行。
               // INTERRUPT_FORCE	0	强制打断类型,即具体操作已由系统强制执行。
               // INTERRUPT_SHARE	1	共享打断类型,即系统不执行具体操作,通过InterruptHint建议并提示应用操作,应用可自行决策下一步处理方式。
               // hintType     中断提示,用于提供中断事件的相关信息。
               // INTERRUPT_HINT_NONE	0  无提示。 元服务API: 从API version 12开始,该接口支持在元服务中使用。
               // INTERRUPT_HINT_RESUME	1   提示音频恢复,应用可主动触发开始渲染或开始采集的相关操作。  此操作无法由系统强制执行,其对应的InterruptForceType一定为INTERRUPT_SHARE类型。

             }
           }
         })
       }catch (e){
         console.log('下载失败')
       }
        })

        Button('直播设置').onClick(async  ()=>{
          let headers: Record<string, string> = {"User-Agent" : "User-Agent-Value"};
          let mediaSource : media.MediaSource = media.createMediaSourceWithUrl("http://xxx",  headers);
          let uuid: number = 1;
          let requests: HashMap<number, media.MediaSourceLoadingRequest> = new HashMap();
          let mediaSourceLoader: media.MediaSourceLoader = {
            open: (request: media.MediaSourceLoadingRequest) => {
              console.info(`Opening resource: ${request.url}`);
              // 成功打开资源,返回唯一的句柄, 保证uuid和request对应。
              uuid += 1;
              requests.set(uuid, request);
              return uuid;
            },
            read: (uuid: number, requestedOffset: number, requestedLength: number) => {
              console.info(`Reading resource with handle ${uuid}, offset: ${requestedOffset}, length: ${requestedLength}`);
              // 判断uuid是否合法、存储read请求,不要在read请求阻塞去推送数据和头信息。
            },
            close: (uuid: number) => {
              console.info(`Closing resource with handle ${uuid}`);
              // 清除当前uuid相关资源。
              requests.remove(uuid);
            }
          };
          mediaSource.setMediaResourceLoaderDelegate(mediaSourceLoader);
          let playStrategy : media.PlaybackStrategy = {
            preferredBufferDuration: 20,
          };
          let player = await AudioPlayerManager.createOrGetAvPlayer();//单例播放,非单例不需要用这个播放器
          player.setMediaSource(mediaSource, playStrategy);
        })

        Text('单例播放视频案例')
          .margin({
            bottom: 20
          })
        VideoView({
          imgUrlPreview:"https://i-avatar.csdnimg.cn/72ceb7652a604f8daa327a5c2d7169e5_weixin_42301175.jpg!1"
        })
      }
    }
    .scrollBar(BarState.Auto)
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(0) // 滚动条宽度
    .friction(0.6)
    .edgeEffect(EdgeEffect.None) //设置滑动效果 //Fade
    .width('100%')
    .id('exampleIndex')
  }
}

6.2 案例代码(视频播放)

ts 复制代码
import { AudioPlayerManager, AVPlayerState } from "../Index"
import { MyLog } from "../src/main/ets/utils/MyLog"
import { audio } from "@kit.AudioKit"

@Component
export struct VideoView {
  xcomponentController: XComponentController = new XComponentController()
  @Prop imgUrlPreview?: string // 默认显示的地址
  private surfaceId: string = 'surfaceId123'
  play(){
    AudioPlayerManager.playByUrl("https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4").then(() => {
      // console.log('AudioPlayerManagement-播放完了哈')
      // 带倍速的 URL 播放
      AudioPlayerManager.callbacks = {
        onStateChange: (state: AVPlayerState) => {
          // 状态变化回调
          MyLog.log('状态变化回调-onStateChange', state)
          if (state == 'initialized') {
            // AudioPlayerManager.setSurfaceId(this.surfaceId) // 视图跟音频结合
            // let audioRenderInfo: audio.AudioRendererInfo = {
            //   usage: audio.StreamUsage.STREAM_USAGE_MOVIE,
            //   rendererFlags: 0
            // }
            // AudioPlayerManager.setAudioRendererInfo(audioRenderInfo)
            // 或者
            const AVPlayer = AudioPlayerManager.getAvPlayer()
            if(AVPlayer){
              AVPlayer.surfaceId = this.surfaceId
              let audioRenderInfo: audio.AudioRendererInfo = {
                usage: audio.StreamUsage.STREAM_USAGE_MOVIE,
                rendererFlags: 0
              }
              AVPlayer.audioRendererInfo = audioRenderInfo
            }
          } else if (state == 'prepared') { // AudioPlayerManager.setSpeed(1) // 设置速度
          } else if (state == 'playing') {
          } else if (state == 'paused') {
          } else if (state == 'stopped') {
          } else if (state == 'released') {
          } else if (state == 'error') {
          }
        },
        onTimeUpdate: (time) => {
          // 进度更新回调
          MyLog.log('onTimeUpdate-进度更新回调'+time)
        },
        onError: (error) => {
          // 错误回调
          MyLog.log('onError-错误回调'+JSON.stringify(error))
        },
        onComplete: () => {
          // 播放完毕
          MyLog.log('onComplete-播放完毕')
        },
        onResetUrl: () => {
          // 当上个视频没播放完毕,就播放下一个视频会被打断,就执行这里
        },
        onAudioInterrupt: (info) => {
          // 不写也是打断,写了就自定义咯
          MyLog.log('1AudioPlayerManagement-onAudioInterrupt', JSON.stringify(info))
          // 被系统声音打断了,比如闹钟
          if (info.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
            // 强制打断类型,即具体操作已由系统强制执行。
            AudioPlayerManager.stop()
            // hintType
          }
          // eventType   音频中断事件类型,开始或是结束。
          //INTERRUPT_TYPE_BEGIN ---1------音频播放中断事件开始。
          // INTERRUPT_TYPE_END  ---2-----音频播放中断事件结束。
          // forceType    操作是由系统强制执行或是由应用程序执行。
          // INTERRUPT_FORCE	0	强制打断类型,即具体操作已由系统强制执行。
          // INTERRUPT_SHARE	1	共享打断类型,即系统不执行具体操作,通过InterruptHint建议并提示应用操作,应用可自行决策下一步处理方式。
          // hintType     中断提示,用于提供中断事件的相关信息。
          // INTERRUPT_HINT_NONE	0  无提示。 元服务API: 从API version 12开始,该接口支持在元服务中使用。
          // INTERRUPT_HINT_RESUME	1   提示音频恢复,应用可主动触发开始渲染或开始采集的相关操作。  此操作无法由系统强制执行,其对应的InterruptForceType一定为INTERRUPT_SHARE类型。

        }
      }
    })

  }
  build() {
Column(){
  XComponent({
    id: this.surfaceId, //组件的唯一标识,支持最大的字符串长度128。
    type: XComponentType.TEXTURE,
    // 用于EGL/OpenGLES和媒体数据写入,开发者定制的绘制内容会和XComponent组件的内容合成后展示到屏幕上。
    // 元服务API: 从API version 11开始,该接口支持在元服务中使用。
    controller: this.xcomponentController// 给组件绑定一个控制器,通过控制器调用组件方法,仅XComponent类型为"surface"时有效。
  }) {
    if (this.imgUrlPreview) {
      // 字幕
      Image(this.imgUrlPreview).width('100%').height('100%') //默认显示的图片
    }
  }
  .onLoad(() => {
    //设置XComponent持有Surface的宽度和高度,仅XComponent类型为"surface"时有效。
    // this.xcomponentController.setXComponentSurfaceSize({ surfaceWidth: 1920, surfaceHeight: 1080 });
    this.surfaceId =
      this.xcomponentController.getXComponentSurfaceId() //获取XComponent对应Surface的ID,供@ohos接口使用,仅XComponent类型为"surface"时有效。
    // 根据屏幕跳转宽高
    // this.xcomponentController.setXComponentSurfaceRect({
    //   surfaceWidth:'100%',
    //   surfaceHeight: '100%',
    // })
    console.log('this.surfaceId', this.surfaceId)
    this.play()
  }).backgroundColor(Color.Black)
}.height(200)
  }
}

🙏内容有问题联系纠正,或者什么意见提供联系Q:867374269

相关推荐
却道天凉_好个秋2 小时前
音视频学习(七十九):LZW编码
音视频·视频压缩·lzw
A向前奔跑10 小时前
前端实现实现视频播放的方案和面试问题
前端·音视频
xianjixiance_11 小时前
Flutter跨平台三方库鸿蒙化适配指南
flutter·华为·harmonyos
夏小鱼的blog11 小时前
【HarmonyOS应用开发入门】第四期:ArkTS语言基础(二)
harmonyos·openharmony
wtrees_松阳12 小时前
【弦断九章·CPU篇】鸿蒙应用性能优化心法
华为·性能优化·harmonyos
2501_9462243112 小时前
旅行记录应用统计分析 - Cordova & OpenHarmony 混合开发实战
javascript·harmonyos·harvester
TEL1892462247713 小时前
IT66612:1对2 HDMI主动分配器,配备EDID RAM和嵌入式MCU
音视频·实时音视频·视频编解码
2501_9462243113 小时前
旅行记录应用外观设置 - Cordova & OpenHarmony 混合开发实战
javascript·harmonyos·harvester
TAEHENGV14 小时前
回收站模块 Cordova 与 OpenHarmony 混合开发实战
android·java·harmonyos