HarmonyOS 鸿蒙Next 请问音频第一次可以正常播放 第二次播放没有声音

发布于 1周前 作者 caililin 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 请问音频第一次可以正常播放 第二次播放没有声音

请问音频第一次可以正常播放,第二次播放没有声音,是什么原因

2 回复

因为setAVPlayerCallback方法在监听到状态切换时会执行相应的播放状态参考代码:

soundUtil.ets

import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
import fs from '@ohos.file.fs';
import fileIo from '@ohos.file.fs';
import { fileUri } from '@kit.CoreFileKit';
export class AVPlayerDemo {
  private avPlayer: media.AVPlayer | undefined
  private count: number = 0;
  private isSeek: boolean = true; // 用于区分模式是否支持seek操作
  private fileSize: number = -1;
  private fd: number = 0;
  private state: string = ''
  constructor() {
    media.createAVPlayer((error: BusinessError, video: media.AVPlayer) => {
      if (video != null) {
        this.avPlayer = video;
        console.info('Succeeded666 in creating AVPlayer');
      } else {
        console.error(`Failed to create AVPlayer, error message:${error.message}`);
      }
    })
  }
  // 注册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.');
          this.avPlayer = await media.createAVPlayer()
          this.avPlayer.prepare()
          break;
        default:
          console.info('AVPlayer state unknown called.');
          break;
      }
    })
  }
  // 以下demo为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例
  async avPlayerFdSrcDemo() {
    // 创建状态机变化回调函数
    this.setAVPlayerCallback(this.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('11582.mp3');
    // let fileDescriptor = await context.resourceManager.getRawFd('1.wav');
    let avFileDescriptor: media.AVFileDescriptor =
      { fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
    this.isSeek = false; // 支持seek操作
    // 为fdSrc赋值触发initialized状态机上报
    this.avPlayer!.fdSrc = avFileDescriptor;
  }
  // 以下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 + '/pCdJNp/1.wav';
    console.log(`path123456: ${path}`);
    // 打开相应的资源文件地址获取fd,并为url赋值触发initialized状态机上报
    let file = await fs.open(path);
    fdPath = fdPath + '' + file.fd;
    this.isSeek = true; // 支持seek操作
    avPlayer.url = fdPath;
  }
  myRawfileCopy() {
    let context = getContext(this) as common.UIAbilityContext;
    context.resourceManager.getRawFileContent("1.wav", (err: BusinessError, data: Uint8Array) => {
      if (err != null) {
        console.error(`open 1.wav failed: ${err.message}`)
      } else {
        let buffer = data.buffer
        let sanboxPath = context.filesDir
        console.log('myRawfileCopy path' + sanboxPath)
        fs.mkdtemp(sanboxPath, async (err, res) => {
          if (err != null) {
            console.error(err?.message)
            return
          }
          console.log("res::" + res)
          let filePath = res + "/1.wav"
          let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
          try {
            fs.writeSync(file.fd, buffer)
            // 拷贝文件到沙箱,为了简便,这里是直接getrawfilecontent然后写入,当文件过大时内存压力会很大,如需优化,可通过buffer进行读取
            fs.close(file.fd)
            // 把沙箱中的文件第一行读出来,验证是否拷贝成功;(fs.readFileSync 方法读取整个文件)
            let data = fileIo.readTextSync(filePath);
            this.avPlayerUrlDemo()
            console.log('myRawfileCopy success ' + data)
          } catch (err) {
            console.log('myRawfileCopy  error')
          }
        })
      }
    })
  }
  async stop() {
    this.avPlayer?.stop()
  }
  async play() {
    this.avPlayer?.play()
  }
  async reset() {
    this.avPlayer?.reset()
  }
  async pause() {
    this.avPlayer?.pause()
  }
  // getState() {
  //   this.avPlayer!.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
  //     return state;
  //   })
  // }
}

Index.ets代码

import { AVPlayerDemo } from '../pages/soundUtil'
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index2 {
  [@State](/user/State) message: string = '播放音频文件';
  private avplayer = new AVPlayerDemo();
  build() {
    Column({ space: 10 }) {
      Button('初始化播放').onClick(() => {
        console.log("开始播放音频文件")
        this.avplayer.avPlayerFdSrcDemo()
      })
      Button('暂停播放').onClick(async () => {
        console.log("暂停播放音频文件")
        this.avplayer.pause()
      })
      Button('恢复播放').onClick(async () => {
        console.log("恢复播放音频文件")
        this.avplayer.play()
      })
      Button('停止播放').onClick(async () => {
        console.log("停止播放音频文件")
        this.avplayer.stop()
      })
      Button('重置播放').onClick(async () => {
        console.log("重置播放音频文件")
        this.avplayer.reset()
      })
    }.width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

修改如下:

Index.ets代码

Button('初始化播放').onClick(() => {
        console.log("开始播放音频文件")
        // this.avplayer.avPlayerFdSrcDemo()
        this.avplayer.avPlayerUrlDemo()
        // this.avplayer.myRawfileCopy()
        // this.avplayer.avPlayerDataSrcSeekDemo()
      })

soundUtil.ets代码

// 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过url属性进行播放示例
async avPlayerUrlDemo() {
  // 创建avPlayer实例对象
  // let avPlayer: media.AVPlayer = await media.createAVPlayer();
  // 创建状态机变化回调函数
  this.setAVPlayerCallback(this.avPlayer!);
  let fdPath = 'fd://';
  // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例
  let context = getContext(this) as common.UIAbilityContext;
  let pathDir = context.filesDir;
  // let path = pathDir + '/pCdJNp/1.wav';
  //这里是写死了沙箱路径,可自行调整
  let path = '/data/storage/el2/base/haps/entry/cache/1.wav';
  console.log(`path123456: ${path}`);
  // 打开相应的资源文件地址获取fd,并为url赋值触发initialized状态机上报
  let file = await fs.open(path);
  fdPath = fdPath + '' + file.fd;
  let avFileDescriptor: media.AVFileDescriptor =
    { fd: file.fd };
  this.isSeek = false; // 支持seek操作
  // 为fdSrc赋值触发initialized状态机上报
  this.avPlayer!.fdSrc = avFileDescriptor;
  // this.isSeek = true; // 支持seek操作
  // this.avPlayer!.url = fdPath;
}

更多关于HarmonyOS 鸿蒙Next 请问音频第一次可以正常播放 第二次播放没有声音的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,针对音频第一次可以正常播放而第二次播放没有声音的问题,可能的原因包括以下几点:

  1. 音频资源未正确释放:首次播放后,音频资源可能未被正确释放或重置,导致第二次播放时资源冲突或状态异常。

  2. 播放状态未重置:音频播放器对象在首次播放后可能未恢复到初始状态,影响后续播放。

  3. 后台权限或策略限制:系统可能对后台音频播放有特定策略,如限制后台音频同时播放的数量或时间。

  4. 系统资源占用:系统资源紧张时,可能无法为第二次播放分配足够的资源。

  5. 音频文件损坏或路径错误:确保第二次播放的音频文件未损坏且路径正确。

  6. 播放接口异常:使用的播放接口在第二次调用时可能出现异常,导致无声。

针对上述问题,可以尝试以下操作(注意,这里不给出具体代码或建议,仅描述可能的方向):

  • 确保每次播放后正确释放和重置音频资源。
  • 检查并更新音频播放器的状态管理。
  • 审查应用的后台权限设置,确保符合系统要求。
  • 优化资源使用,避免系统资源紧张。
  • 验证音频文件的完整性和路径正确性。
  • 调用播放接口时,注意异常处理。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部