2024-07-10 14:09:42 +08:00
|
|
|
import media from '@ohos.multimedia.media';
|
|
|
|
|
import Prompt from '@system.prompt';
|
2024-07-11 16:16:43 +08:00
|
|
|
import url from '@ohos.url';
|
2024-07-31 13:47:40 +08:00
|
|
|
import fileuri from "@ohos.file.fileuri";
|
|
|
|
|
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
|
2024-07-10 14:09:42 +08:00
|
|
|
|
|
|
|
|
const TAG = 'VoiceAnnounce'
|
|
|
|
|
|
|
|
|
|
export default class VoiceAnnounce{
|
|
|
|
|
|
|
|
|
|
//队列时候立马终止
|
|
|
|
|
private isStopped:Boolean
|
2024-07-11 16:16:43 +08:00
|
|
|
private queue:{
|
|
|
|
|
url:string,
|
|
|
|
|
callback?:Function
|
|
|
|
|
}[]
|
|
|
|
|
private newQueue:{
|
|
|
|
|
url:string,
|
|
|
|
|
callback?:Function
|
|
|
|
|
}[]
|
2024-07-10 14:09:42 +08:00
|
|
|
private pendingQueue:String[]
|
|
|
|
|
private callback:Function;
|
|
|
|
|
constructor() {
|
|
|
|
|
this.isStopped = false;
|
|
|
|
|
this.queue = []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async playAudio(urls:string[],shit?:boolean,callback?:Function){
|
|
|
|
|
const {isStopped,queue} = this;
|
2024-07-11 16:16:43 +08:00
|
|
|
const tempUrls = urls.map((url,index)=>{
|
|
|
|
|
return {
|
|
|
|
|
url,
|
|
|
|
|
callback:(index === urls.length - 1)?callback:undefined
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-07-10 14:09:42 +08:00
|
|
|
if(shit){
|
|
|
|
|
//队列清空,重新初始化
|
|
|
|
|
this.isStopped = true;
|
2024-07-11 16:16:43 +08:00
|
|
|
this.newQueue = tempUrls
|
2024-07-10 14:09:42 +08:00
|
|
|
}
|
|
|
|
|
if(queue.length){
|
|
|
|
|
//队列续上
|
2024-07-11 16:16:43 +08:00
|
|
|
this.queue = this.queue.concat(tempUrls)
|
2024-07-10 14:09:42 +08:00
|
|
|
|
|
|
|
|
}else{
|
2024-07-11 16:16:43 +08:00
|
|
|
this.queue = tempUrls
|
2024-07-10 14:09:42 +08:00
|
|
|
await this.executeQueue()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async executeQueue(){
|
|
|
|
|
const avPlayer = new AVPlayer();
|
|
|
|
|
const go = async () => {
|
2024-07-11 16:16:43 +08:00
|
|
|
const {queue,isStopped,newQueue} = this;
|
2024-07-10 14:09:42 +08:00
|
|
|
if(isStopped){
|
|
|
|
|
//清空原来队列
|
|
|
|
|
this.queue = newQueue
|
|
|
|
|
this.isStopped = false;
|
|
|
|
|
await go()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-11 16:16:43 +08:00
|
|
|
await avPlayer.play(queue[0].url,queue[0].callback);
|
2024-07-10 14:09:42 +08:00
|
|
|
this.queue.shift();
|
|
|
|
|
console.info(TAG,JSON.stringify(this.queue),'堆栈弹出');
|
|
|
|
|
if(this.queue.length){
|
|
|
|
|
await go()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await go()
|
|
|
|
|
avPlayer.avPlayerStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AVPlayer {
|
|
|
|
|
|
|
|
|
|
public avPlayer:any = null;
|
|
|
|
|
|
|
|
|
|
private voiceUrl: string[];
|
|
|
|
|
private voiceStatus: 'completed' | 'playing'
|
|
|
|
|
private endCallback:Function
|
|
|
|
|
constructor() {}
|
|
|
|
|
|
|
|
|
|
// 以下为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例
|
|
|
|
|
async play(name,callback) {
|
2024-07-31 13:47:40 +08:00
|
|
|
let isInSD = true
|
|
|
|
|
try {
|
|
|
|
|
//检查SD中的语音
|
|
|
|
|
console.info('surenjun name',name)
|
|
|
|
|
console.info('surenjun name',name.split('/')[1])
|
|
|
|
|
let playSrc = await this.queryFile(name.split('/')[1]);
|
|
|
|
|
let fdPath = await playSrc.open('r')
|
|
|
|
|
let audioPlayer = media.createAudioPlayer()
|
|
|
|
|
console.info('surenjun fdPath=>',fdPath)
|
|
|
|
|
audioPlayer.on('dataLoad', () => {
|
|
|
|
|
this.voiceStatus = 'playing'
|
|
|
|
|
audioPlayer.play()
|
|
|
|
|
})
|
|
|
|
|
return new Promise(async (resolve)=>{
|
|
|
|
|
audioPlayer.on('finish', () => {
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
this.voiceStatus = 'completed'
|
|
|
|
|
if(callback){
|
|
|
|
|
callback()
|
|
|
|
|
}
|
|
|
|
|
audioPlayer.stop();
|
|
|
|
|
audioPlayer.reset()
|
|
|
|
|
audioPlayer.release()
|
|
|
|
|
resolve(true)
|
|
|
|
|
})
|
|
|
|
|
audioPlayer.reset()
|
|
|
|
|
audioPlayer.src = `fd://${fdPath}`
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}catch (e){
|
|
|
|
|
console.info('surenjun fdPath=>',JSON.stringify(e))
|
|
|
|
|
isInSD = false;
|
|
|
|
|
}
|
|
|
|
|
if(!isInSD){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//检查SD中的语音
|
2024-07-10 14:09:42 +08:00
|
|
|
this.endCallback = callback
|
|
|
|
|
const avPlayer = await media.createAVPlayer();
|
|
|
|
|
this.avPlayer = avPlayer;
|
2024-07-31 13:47:40 +08:00
|
|
|
|
2024-07-10 14:09:42 +08:00
|
|
|
return new Promise(async (resolve,reject) => {
|
|
|
|
|
let url = ''
|
|
|
|
|
await this.setAVPlayerCallback(()=>{
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
resolve()
|
|
|
|
|
});
|
|
|
|
|
try {
|
|
|
|
|
url = await globalThis.context.resourceManager.getRawFd(name);
|
|
|
|
|
this.avPlayer.fdSrc = url;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Prompt.showToast({
|
|
|
|
|
message: `${name}语音文件不存在`,
|
|
|
|
|
duration: 4000
|
|
|
|
|
});
|
|
|
|
|
resolve(1)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-07-31 13:47:40 +08:00
|
|
|
|
|
|
|
|
async queryFile(displayName): Promise<mediaLibrary.FileAsset> {
|
|
|
|
|
const mediaLib = mediaLibrary.getMediaLibrary(globalThis.context);
|
|
|
|
|
let ret
|
|
|
|
|
let fetchOp = {
|
|
|
|
|
selections: `media_type=? AND display_name = ?`,
|
|
|
|
|
selectionArgs: [`${mediaLibrary.MediaType.AUDIO}`,displayName],
|
|
|
|
|
};
|
|
|
|
|
let fileResult = await mediaLib.getFileAssets(fetchOp);
|
|
|
|
|
let retCount = fileResult.getCount();
|
|
|
|
|
console.info('surenjun retCount=>',retCount)
|
|
|
|
|
if (retCount > 0) {
|
|
|
|
|
ret = fileResult.getFirstObject();
|
|
|
|
|
return Promise.resolve(ret);
|
|
|
|
|
}else{
|
|
|
|
|
return Promise.reject(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:09:42 +08:00
|
|
|
//音频播放队列
|
|
|
|
|
public releasePlayer() {
|
|
|
|
|
this.avPlayer.release();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-11 16:16:43 +08:00
|
|
|
avPlayerStop = ()=> {
|
2024-07-10 14:09:42 +08:00
|
|
|
this.avPlayer && this.avPlayer.stop()
|
|
|
|
|
this.avPlayer && this.avPlayer.reset()
|
|
|
|
|
this.avPlayer && this.avPlayer.release()
|
|
|
|
|
}
|
|
|
|
|
// 注册avplayer回调函数
|
|
|
|
|
setAVPlayerCallback(callBack) {
|
|
|
|
|
|
|
|
|
|
this.avPlayer.on('error', (err) => {
|
|
|
|
|
this.avPlayer && this.avPlayer.stop()
|
|
|
|
|
this.avPlayer && this.avPlayer.reset()
|
|
|
|
|
this.avPlayer && this.avPlayer.release()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
let num = 0;
|
|
|
|
|
// 状态机变化回调函数
|
|
|
|
|
this.avPlayer.on('stateChange', async (state, reason) => {
|
|
|
|
|
const {endCallback} = this;
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 'idle': // 成功调用reset接口后触发该状态机上报
|
|
|
|
|
break;
|
|
|
|
|
case 'initialized': // avplayer 设置播放源后触发该状态上报
|
|
|
|
|
this.avPlayer.prepare()
|
|
|
|
|
break;
|
|
|
|
|
case 'prepared': // prepare调用成功后上报该状态机
|
|
|
|
|
this.avPlayer.play();
|
|
|
|
|
this.voiceStatus = 'playing'
|
|
|
|
|
break;
|
|
|
|
|
case 'playing': // play成功调用后触发该状态机上报
|
|
|
|
|
break;
|
|
|
|
|
case 'paused': // pause成功调用后触发该状态机上报
|
|
|
|
|
break;
|
|
|
|
|
case 'completed': // 播放结束后触发该状态机上报
|
|
|
|
|
this.voiceStatus = 'completed'
|
|
|
|
|
this.avPlayer.stop(); //调用播放结束接口
|
|
|
|
|
if(endCallback){
|
|
|
|
|
endCallback()
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'stopped': // stop接口成功调用后触发该状态机上报
|
|
|
|
|
this.avPlayer.reset(); // 调用reset接口初始化avplayer状态
|
|
|
|
|
callBack()
|
|
|
|
|
break;
|
|
|
|
|
case 'released':
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|