HarmonyOS 鸿蒙Next 无法播放rawfile里的wav文件
HarmonyOS 鸿蒙Next 无法播放rawfile里的wav文件
结合文档中的示例https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/using-avplayer-for-playback-V5,使用AVPlayer播放音频
点击播放音乐2文本调用setAVPlayerCallBack()方法
通过fdSrc播放rawfile中的音频,结果播放不出来,使用debug信息如下图所示
求助大佬
3 回复
本地测试过正常播放的呀,下面是我的demo。在resource/rawfile下面放一个01.wav。你也可以修改代码中的avPlayerFdSrcDemo方法中的音频文件名。
import { media } from '[@kit](/user/kit).MediaKit';
import { fileIo as fs } from '[@kit](/user/kit).CoreFileKit';
import { common } from '[@kit](/user/kit).AbilityKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { audio } from '[@kit](/user/kit).AudioKit';
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.audioRendererInfo = {
usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
rendererFlags: 0
}
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 {
setTimeout(() => {
console.info('AVPlayer is playing wait to pause');
avPlayer.pause(); // 播放3s后调用暂停接口暂停播放
}, 3000)
}
this.count++;
break;
case 'paused': // pause成功调用后触发该状态机上报
console.info('AVPlayer state paused called.');
setTimeout(() => {
console.info('AVPlayer paused wait to play again');
avPlayer.play(); // 暂停3s后再次调用播放接口开始播放
}, 3000)
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.wav');
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';
}
}
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
av:AVPlayerDemo = new AVPlayerDemo()
build() {
Column() {
Button('play local')
.onClick(() => {
this.av.avPlayerFdSrcDemo();
})
}
}
}
楼主您好,上述文档中的示例代码,在setAVPlayerCallback函数的playing的状态机里,有一个else的分支是 播放3s后调用暂停接口暂停播放,把这个分支注释掉试试能否播放呢
作为IT专家,针对您提出的“HarmonyOS 鸿蒙Next 无法播放rawfile里的wav文件”的问题,以下是一些可能的原因及解决方案:
- 文件格式及采样率:请确认wav文件的格式和采样率是否被HarmonyOS 鸿蒙Next系统支持。部分系统可能不支持低采样率的wav文件,如4000Hz,尝试使用更高采样率的wav文件看是否能正常播放。
- 文件放置位置:确保wav文件已正确放置在项目的resources/rawfile目录下,并在manifest.json中声明了该资源。
- 路径及权限:使用RawFileDescriptor或相关API访问时,确保路径正确无误,并检查应用是否有访问rawfile的权限(虽然通常不需要特殊权限)。
- API调用:如果使用的是特定的API或方法,请确保API的调用方式正确,参数无误。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。在联系客服时,请提供详细的问题描述、设备型号、系统版本等信息,以便客服人员更快地定位并解决问题。