AVplayer开发音频播放功能

AVplayer开发音频播放功能

HarmonyOS
2024-05-20 21:06:46
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
HearMe_cn

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

AVPlayer提供功能完善一体化播放能力,应用只需要提供流媒体来源,不负责数据解析和解码就可达成播放效果。

音乐类应用通过调用JS接口层提供的AVPlayer接口实现相应功能时,框架层会通过播放服务(Player Framework)将资源解析成音频数据流(PCM),音频数据流经过软件解码后输出至音频服务(Audio Framework),由音频服务输出至音频驱动渲染,实现音频播放功能。

1.使用的核心API  



事件类型




说明


stateChange

必要事件,监听播放器的state属性改变。

error

必要事件,监听播放器的错误信息。

durationUpdate

用于进度条,监听进度条长度,刷新资源时长。

timeUpdate

用于进度条,监听进度条当前位置,刷新当前时间。

seekDone

响应API调用,监听seek()请求完成情况。

当使用seek()跳转到指定播放位置后,如果seek操作成功,将上报该事件。

speedDone

响应API调用,监听setSpeed()请求完成情况。

当使用setSpeed()设置播放倍速后,如果setSpeed操作成功,将上报该事件。

volumeChange

响应API调用,监听setVolume()请求完成情况。

当使用setVolume()调节播放音量后,如果setVolume操作成功,将上报该事件。

bufferingUpdate

用于网络播放,监听网络播放缓冲信息,用于上报缓冲百分比以及缓存播放进度。

audioInterrupt

监听音频焦点切换信息,搭配属性audioInterruptMode使用。

如果当前设备存在多个音频正在播放,音频焦点被切换(即播放其他媒体如通话等)时将上报该事件,应用可以及时处理。


2.核心代码解释

相关demo如下

import media from '@ohos.multimedia.media'; 
import fs from '@ohos.file.fs'; 
import common from '@ohos.app.ability.common'; 
import { BusinessError } from '@ohos.base'; 
  
export class AVPlayerDemo { 
  private count: number = 0; 
  private isSeek: boolean = true; // 用于区分模式是否支持seek操作 
  private fileSize: number = -1; 
  private fd: number = 0; 
  // 注册avplayer回调函数 
  setAVPlayerCallback(avPlayer: media.AVPlayer) { 
    // seek操作结果回调函数 
    avPlayer.on('seekDone', (seekDoneTime: number) => { 
      console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`); 
    }) 
    // error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程 
    avPlayer.on('error', (err: BusinessError) => { 
      console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`); 
      avPlayer.reset(); // 调用reset重置资源,触发idle状态 
    }) 
    // 状态机变化回调函数 
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => { 
      switch (state) { 
        case 'idle': // 成功调用reset接口后触发该状态机上报 
          console.info('AVPlayer state idle called.'); 
          avPlayer.release(); // 调用release接口销毁实例对象 
          break; 
        case 'initialized': // avplayer 设置播放源后触发该状态上报 
          console.info('AVPlayer state initialized called.'); 
          avPlayer.prepare(); 
          break; 
        case 'prepared': // prepare调用成功后上报该状态机 
          console.info('AVPlayer state prepared called.'); 
          avPlayer.play(); // 调用播放接口开始播放 
          break; 
        case 'playing': // play成功调用后触发该状态机上报 
          console.info('AVPlayer state playing called.'); 
          if (this.count !== 0) { 
            if (this.isSeek) { 
              console.info('AVPlayer start to seek.'); 
              avPlayer.seek(avPlayer.duration); //seek到音频末尾 
            } else { 
              // 当播放模式不支持seek操作时继续播放到结尾 
              console.info('AVPlayer wait to play end.'); 
            } 
          } else { 
            avPlayer.pause(); // 调用暂停接口暂停播放 
          } 
          this.count++; 
          break; 
        case 'paused': // pause成功调用后触发该状态机上报 
          console.info('AVPlayer state paused called.'); 
          avPlayer.play(); // 再次播放接口开始播放 
          break; 
        case 'completed': // 播放结束后触发该状态机上报 
          console.info('AVPlayer state completed called.'); 
          avPlayer.stop(); //调用播放结束接口 
          break; 
        case 'stopped': // stop接口成功调用后触发该状态机上报 
          console.info('AVPlayer state stopped called.'); 
          avPlayer.reset(); // 调用reset接口初始化avplayer状态 
          break; 
        case 'released': 
          console.info('AVPlayer state released called.'); 
          break; 
        default: 
          console.info('AVPlayer state unknown called.'); 
          break; 
      } 
    }) 
  } 
  
  // 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过url属性进行播放示例 
  async avPlayerUrlDemo() { 
    // 创建avPlayer实例对象 
    let avPlayer: media.AVPlayer = await media.createAVPlayer(); 
    // 创建状态机变化回调函数 
    this.setAVPlayerCallback(avPlayer); 
    let fdPath = 'fd://'; 
    // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例 
    let context = getContext(this) as common.UIAbilityContext; 
    let pathDir = context.filesDir; 
    let path = pathDir + '/01.mp3'; 
    // 打开相应的资源文件地址获取fd,并为url赋值触发initialized状态机上报 
    let file = await fs.open(path); 
    fdPath = fdPath + '' + file.fd; 
    this.isSeek = true; // 支持seek操作 
    avPlayer.url = fdPath; 
  } 
  
  // 以下demo为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例 
  async avPlayerFdSrcDemo() { 
    // 创建avPlayer实例对象 
    let avPlayer: media.AVPlayer = await media.createAVPlayer(); 
    // 创建状态机变化回调函数 
    this.setAVPlayerCallback(avPlayer); 
    // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址 
    // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度 
    let context = getContext(this) as common.UIAbilityContext; 
    let fileDescriptor = await context.resourceManager.getRawFd('01.mp3'); 
    let avFileDescriptor: media.AVFileDescriptor = 
      { fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length }; 
    this.isSeek = true; // 支持seek操作 
    // 为fdSrc赋值触发initialized状态机上报 
    avPlayer.fdSrc = avFileDescriptor; 
  } 
  
  // 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放(seek模式)示例 
  async avPlayerDataSrcSeekDemo() { 
    // 创建avPlayer实例对象 
    let avPlayer: media.AVPlayer = await media.createAVPlayer(); 
    // 创建状态机变化回调函数 
    this.setAVPlayerCallback(avPlayer); 
    // dataSrc播放模式的的播放源地址,当播放为Seek模式时fileSize为播放文件的具体大小,下面会对fileSize赋值 
    let src: media.AVDataSrcDescriptor = { 
      fileSize: -1, 
      callback: (buf: ArrayBuffer, length: number, pos: number | undefined) => { 
        let num = 0; 
        if (buf == undefined || length == undefined || pos == undefined) { 
          return -1; 
        } 
        num = fs.readSync(this.fd, buf, { offset: pos, length: length }); 
        if (num > 0 && (this.fileSize >= pos)) { 
          return num; 
        } 
        return -1; 
      } 
    } 
    let context = getContext(this) as common.UIAbilityContext; 
    // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例 
    let pathDir = context.filesDir; 
    let path = pathDir  + '/01.mp3'; 
    await fs.open(path).then((file: fs.File) => { 
      this.fd = file.fd; 
    }) 
    // 获取播放文件的大小 
    this.fileSize = fs.statSync(path).size; 
    src.fileSize = this.fileSize; 
    this.isSeek = true; // 支持seek操作 
    avPlayer.dataSrc = src; 
  } 
  
  // 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放(No seek模式)示例 
  async avPlayerDataSrcNoSeekDemo() { 
    // 创建avPlayer实例对象 
    let avPlayer: media.AVPlayer = await media.createAVPlayer(); 
    // 创建状态机变化回调函数 
    this.setAVPlayerCallback(avPlayer); 
    let context = getContext(this) as common.UIAbilityContext; 
    let src: media.AVDataSrcDescriptor = { 
      fileSize: -1, 
      callback: (buf: ArrayBuffer, length: number) => { 
        let num = 0; 
        if (buf == undefined || length == undefined) { 
          return -1; 
        } 
        num = fs.readSync(this.fd, buf); 
        if (num > 0) { 
          return num; 
        } 
        return -1; 
      } 
    } 
    // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例 
    let pathDir = context.filesDir; 
    let path = pathDir  + '/01.mp3'; 
    await fs.open(path).then((file: fs.File) => { 
      this.fd = file.fd; 
    }) 
    this.isSeek = false; // 不支持seek操作 
    avPlayer.dataSrc = src; 
  } 
  
  // 以下demo为通过url设置网络地址来实现播放直播码流的demo 
  async avPlayerLiveDemo() { 
    // 创建avPlayer实例对象 
    let avPlayer: media.AVPlayer = await media.createAVPlayer(); 
    // 创建状态机变化回调函数 
    this.setAVPlayerCallback(avPlayer); 
    this.isSeek = false; // 不支持seek操作 
    avPlayer.url = 'http://xxx.xxx.xxx.xxx:xx/xx/index.m3u8'; 
  } 
}

注明适配的版本信息

  • IDE:DevEco Studio 4.0.1.501
  • SDK:HarmoneyOS 4.0.10.11
分享
微博
QQ
微信
回复
2024-05-21 16:51:56
相关问题
使用AudioRenderer开发音频播放功能
482浏览 • 1回复 待解决
使用AudioCapturer开发音频录制功能
581浏览 • 1回复 待解决
AVPlayer实现音频播放(c++侧)
421浏览 • 1回复 待解决
SoundPool实现音频播放功能
618浏览 • 1回复 待解决
鸿蒙JS开发音频管理,导入media错误
2657浏览 • 1回复 已解决
AVPlayer实现视频播放
286浏览 • 1回复 待解决
avplayer播放视频demo
357浏览 • 1回复 待解决
使用AVPlayer实现视频播放
335浏览 • 1回复 待解决
AudioCapturer录音+AudioRenderer播放音频
648浏览 • 1回复 待解决
OH _Audio播放音频问题
633浏览 • 1回复 待解决
音频播放长时任务不生效
598浏览 • 1回复 待解决
鸿蒙 如何使用 player 播放网络音频
6009浏览 • 1回复 已解决
使用AudioRenderer播放pcm音频流失败
616浏览 • 1回复 待解决
怎么使用player播放网络音频呢?
2324浏览 • 1回复 待解决
SoundPool播放音频是否支持WMV格式
787浏览 • 1回复 待解决
鸿蒙-如何实现播放一段音频
9806浏览 • 2回复 待解决
鸿蒙Dev远程真机能否播放音频
4040浏览 • 1回复 待解决
音频录制开发相关问题
4460浏览 • 1回复 待解决