H5全局全功能播放器实现,暂不支持仅缓冲部分播放。 此播放器功能支持播放区间,支持淡入淡出、播放控制, seek控制、支持个性化配置。
H5Audio方法介绍
arduino
// HTML <audio> 元素支持一系列事件,这些事件可以帮助您管理音频的播放、暂停、加载等状态
// onloadstart: 当浏览器开始加载音频时触发。
// onloadedmetadata: 当浏览器已加载音频的元数据时触发。
// onloadeddata: 当浏览器已加载音频的全部数据时触发。
// oncanplay: 当浏览器可以开始播放音频时触发。
// oncanplaythrough: 当浏览器预计可以在不停顿的情况下播放音频时触发。
// onplay: 当音频开始播放时触发。
// onplaying: 当音频正在播放时触发。
// onpause: 当音频暂停时触发。
// onended: 当音频播放结束时触发。
// onerror: 当音频加载出错时触发。
// onprogress: 当音频正在下载时触发,以便显示下载进度。
// ontimeupdate: 当音频播放位置发生变化时触发,以便更新播放进度条等。
// HTML <audio> 元素本身没有方法,但可以通过JavaScript来操作它。以下是一些常用的通过 JavaScript 操作 <audio> 元素的方法:
// play(): 开始播放音频。
// pause(): 暂停音频播放。
// load(): 重新加载音频。
// canPlayType(type): 返回一个字符串,指示浏览器是否能够播放指定类型的音频文件。
// currentTime: 属性,用于获取或设置音频的当前播放位置。
// volume: 属性,用于获取或设置音频的音量。
// muted: 属性,用于获取或设置音频是否静音。
// duration: 属性,返回音频的总时长。
// seekable: 属性,返回一个 TimeRanges 对象,表示音频可寻址的时间范围。
// ended: 属性,返回一个布尔值,指示音频是否已经播放结束。
实现
kotlin
const globleConfig = {
volume: 1,
analyserFftSize : 2048,
mapType: 'url' , // 当存在重复url时推荐给url添加模块后缀的方式避免渲染重复
}
const defaultConfig = {
endedToStart: true, // 播放结束后是否回归零位置
loop: false, // 是否循环播放
fadeInTime: 0, // 淡入时间 暂没支持
fadeOutTime: 0, // 淡出时间 暂没支持
volumeGain: 0, // 音量偏移,当前歌曲音量降低或增加0-1,音量最大为1
analyser: false, // 创建频谱直方图
canSeekNotCurrent: false, // 当不是当前播放时是否可以调整下次播放位置
autoToStartIfNotCurrent: true, // 当不是当前时是否自动归零
}
export class GlobalAudioPlayer {
constructor() {
if (GlobalAudioPlayer.instance) {
return GlobalAudioPlayer.instance;
}
this.initAudio();
GlobalAudioPlayer.instance = this;
}
initAudio() {
this.audio = new Audio();
this.globleAudioAnalyser = null;
this.players = {}; // 存储每个URL对应的播放数据
this.lastUrl = null; // 记录上一个播放的URL
this.currentUrl = null // 记录当前正在播放的URL
this.currentPlayer = null; // 记录当前播放器
this.changeUrlListener=[];
this.globalListenerMap= {
'playStateChange':[],
'curPlayEnded':[],
'curPlayUrlChange':[],
};
this.audio.crossOrigin = 'anonymous';
this.checkNetworkStatus();
this.audio.addEventListener('loadstart', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('loadstart', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onloadstart', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', true)
});
this.audio.addEventListener('loadedmetadata', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('loadedmetadata', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onloadedmetadata', ...args)
if(this.audio.duration!=Infinity){
this.players[this.currentUrl].duration = this.audio.duration;
}
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onDurationChange', this.getDuration(this.players[this.currentUrl]))
});
this.audio.addEventListener('loadeddata', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('loadeddata', ...args);
if(this.audio.duration!=Infinity){
this.players[this.currentUrl].duration = this.audio.duration;
}
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onloadeddata')
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onDurationChange', this.getDuration(this.players[this.currentUrl]))
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
});
this.audio.addEventListener('canplay', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('canplay', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'oncanplay', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
});
this.audio.addEventListener('canplaythrough', (...args) => {
if(!this.currentUrl){
return;
}
if(!this.currentPlayer.isPlaying){
this.pause(this.currentUrl);
}
// console.log('canplaythrough', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'oncanplaythrough', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
});
this.audio.addEventListener('play', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('play', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onplay', ...args)
// this.triggerListenerBroadcast(this.players[this.currentUrl], 'onPlayStateChange', true)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
});
this.audio.addEventListener('playing', (...args) => {
if(!this.currentUrl){
return;
}
this.currentPlayer.isPlaying = true;
// console.log('playing', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'oncanplaythrough', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onPlayStateChange', true)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
});
this.audio.addEventListener('pause', (...args) => {
if(!this.currentUrl){
return;
}
this.currentPlayer.isPlaying = false;
// console.log('pause', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onpause', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onPlayStateChange', false)
});
this.audio.addEventListener('ended', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('ended', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onended', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onPlayStateChange', false)
const { endedToStart, loop, fadeInTime, fadeOutTime } = this.players[this.currentUrl].personalizedConfig;
if (endedToStart) {
this.audio.currentTime = 0;
}
if (loop) {
this.paly(this.currentUrl);
}else{
this.pause(this.currentUrl);
}
this.triggerGlobleListenerBroadcast('curPlayEnded',{
currentUrl:this.currentUrl,
player:this.players[this.currentUrl]
})
});
this.audio.addEventListener('error', (...args) => {
console.error('addEventListener__error', ...args);
if(!this.currentUrl){
return;
}
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onerror', ...args)
});
this.audio.addEventListener('progress', (...args) => {
if(!this.currentUrl){
return;
}
// console.log('progress', ...args);
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onprogress')
if (this.audio.readyState >= 2) {
if((this.audio.buffered.end(0) / this.audio.duration) == (this.audio.currentTime / this.audio.duration)){
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', true)
}
}
});
this.audio.addEventListener('timeupdate', (...args) => {
// console.log('timeupdate', ...args);
if(!this.currentUrl){
return;
}
this.triggerListenerBroadcast(this.players[this.currentUrl], 'ontimeupdate', ...args)
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onLoadingStateChange', false)
const { endedToStart, loop, fadeInTime, fadeOutTime, volumeGain } = this.players[this.currentUrl].personalizedConfig;
let {clipStart, clipEnd } = this.checkClipTime(this.players[this.currentUrl]);
if(clipStart>=0 && clipEnd > clipStart){
let currentTime = this.audio.currentTime;
if(currentTime < clipStart || currentTime >= clipEnd){
if(currentTime < clipStart){
this.audio.currentTime = clipStart;
}else{
if (endedToStart) {
this.audio.currentTime = clipStart;
}else{
this.audio.currentTime = clipEnd;
}
if (loop) {
this.paly(this.currentUrl);
}else{
this.pause(this.currentUrl);
}
this.triggerGlobleListenerBroadcast('curPlayEnded',{
currentUrl:this.currentUrl,
player:this.players[this.currentUrl]
})
}
}
}else {
clipEnd = this.audio.duration
}
let volume = globleConfig.volume + volumeGain;
if(volume < 0){
volume = 0;
}else if(volume > 1){
volume = 1;
}
if(fadeInTime > 0 && this.audio.currentTime <= clipStart + fadeInTime){
this.audio.volume = (this.audio.currentTime - clipStart) / fadeInTime * volume;
}else if(fadeOutTime > 0 && this.audio.currentTime >= clipEnd-fadeOutTime){
this.audio.volume = (clipEnd - this.audio.currentTime) / fadeOutTime * volume;
}else{
this.audio.volume = volume;
}
this.players[this.currentUrl].currentTime = this.audio.currentTime;
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onPositionChange', this.getPositionData(this.players[this.currentUrl]));
if(this.players[this.currentUrl].personalizedConfig.analyser){
this.triggerListenerBroadcast(this.players[this.currentUrl], 'onAudioAnalyserChange', this.getAnalyserData(this.players[this.currentUrl]));
}
if(!this.currentPlayer.isPlaying){
this.pause(this.currentUrl);
}
});
}
getUuid(){
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
splitArray(arr, count){
const size = Math.ceil(arr.length ?? 0) / count;
return arr.length
? arr.reduce(
(res, cur) => (
res[res.length - 1].length < size
? res[res.length - 1].push(cur)
: res.push([cur]),
res
),
[[]]
)
: [];
}
formatTime(secs) {
if(isNaN(Number(secs))){
return '00:00';
}
secs = Math.ceil(secs);
const minutes = Math.floor(secs / 60) || 0;
const seconds = Math.floor(secs - minutes * 60) || 0;
return `${String(minutes).padStart(2,0)}:${String(seconds).padStart(2,0)}`;
}
canPlayType(type){
return this.audio.canPlayType(type);
}
setVolume(volume){
globleConfig.volume = volume;
this.audio.volume = volume;
}
checkClipTime(player){
let {clipStart, clipEnd, duration} = player;
clipStart = clipStart>0 ? clipStart > duration ? 0 : clipStart : 0;
clipEnd = clipEnd >0 ? clipEnd > duration ? duration : clipEnd : 0;
return {
clipStart,
clipEnd
}
}
getDuration(player){
const {clipStart, clipEnd } = this.checkClipTime(player);
const { duration } = player;
if(clipStart >= 0 && clipEnd > clipStart){
return {
duration: clipEnd - clipStart,
durationTime: this.formatTime(clipEnd - clipStart),
sourceDuration: duration,
sourceDurationTime: this.formatTime(duration)
}
}else{
return {
duration: duration,
durationTime: this.formatTime(duration),
sourceDuration: duration,
sourceDurationTime: this.formatTime(duration)
}
}
}
getPositionData(player){
const {clipStart, clipEnd } = this.checkClipTime(player);
const {currentTime, duration} = player;
if(clipStart>=0 && clipEnd > clipStart){
return {
start: 0,
startTime: this.formatTime(0),
end: (clipEnd-clipStart),
endTime: this.formatTime(clipEnd-clipStart),
current: currentTime-clipStart,
currentTime: this.formatTime(currentTime-clipStart),
progress: (currentTime-clipStart)/(clipEnd-clipStart),
sourceStart: 0,
sourceStartTime: this.formatTime(0),
sourceEnd: duration,
sourceEndTime: this.formatTime(duration),
sourceCurrent: currentTime,
sourceCurrentTime: this.formatTime(currentTime),
sourceProgress: currentTime/duration,
}
}else{
return {
start: 0,
startTime: this.formatTime(0),
end: duration,
endTime: this.formatTime(duration),
current: currentTime,
currentTime: this.formatTime(currentTime),
progress: currentTime/duration,
sourceStart: 0,
sourceStartTime: this.formatTime(0),
sourceEnd: duration,
sourceEndTime: this.formatTime(duration),
sourceCurrent: currentTime,
sourceCurrent: this.formatTime(currentTime),
sourceProgress: currentTime/duration,
}
}
}
// registChangeUrlListener(listener){
// if(!this.changeUrlListener.includes(listener)){
// this.changeUrlListener.push(listener);
// }
// }
// releaseChangeUrlListener(listener){
// const index = this.changeUrlListener.indexOf(listener);
// if(index>-1){
// this.changeUrlListener.splice(index, 1);
// }
// }
registGlobleListener(eventName,listener){
// this.globalListenerMap= {
// 'playStateChange':[],
// 'curPlayEnded':[],
// 'curPlayUrlChange':[],
// }
const listeners = this.globalListenerMap[eventName];;
if(listeners && !listeners.includes(listener)){
listeners.push(listener);
}
}
releaseGlobleListener(eventName,listener){
const listeners = this.globalListenerMap[eventName];
const index = listeners?.indexOf(listener);
if(index>-1){
listeners.splice(index, 1);
}
}
triggerGlobleListenerBroadcast(eventName, ...args){
const listeners = this.globalListenerMap[eventName];
if(listeners){
listeners.forEach((listener)=>{
listener(...args);
})
}
}
triggerListenerBroadcast(player, listenerName, ...args){
player && player.listeners.forEach((listener)=>{
listener[listenerName]&&listener[listenerName](...args);
})
if(listenerName=="onPlayStateChange"){
this.triggerGlobleListenerBroadcast('playStateChange', {
isPlaying: args[0],
lastUrl: this.lastUrl,
player: player,
currentUrl: this.currentUrl
})
}
}
setupAudioContext = () => {
try {
if (typeof AudioContext !== 'undefined') {
return new AudioContext();
} else if (typeof webkitAudioContext !== 'undefined') {
return new webkitAudioContext();
} else {
return null;
}
} catch(e) {
return null;
}
}
openAudioAnalyser= (player)=> {
let isAnalyser = player.personalizedConfig?.analyser;
if(isAnalyser){
if(!this.globleAudioAnalyser){
let audioContext = this.setupAudioContext();
try{
audioContext.resume().then(() => {
let analyser = audioContext.createAnalyser();
analyser.fftSize = globleConfig.analyserFftSize;
let analyserMediaElementSource = audioContext.createMediaElementSource(this.audio);
analyserMediaElementSource.connect(analyser);
analyserMediaElementSource.connect(audioContext.destination);
this.globleAudioAnalyser = {
audioContext,
analyser,
analyserMediaElementSource
}
player.audioAnalyser = {
...player.audioAnalyser,
...this.globleAudioAnalyser,
active: true,
}
});
}catch(e){
console.log("initAudioAnalyser__error", e);
}
} else {
// this.globleAudioAnalyser.audioContext.resume()
player.audioAnalyser = {
...player.audioAnalyser,
...this.globleAudioAnalyser,
active: true,
}
}
}
}
closeAudioAnalyser= async (player, isDestroy = false)=> {
let isAnalyser = player.personalizedConfig?.analyser;
let { audioContext, analyser, analyserMediaElementSource} = player.audioAnalyser;
if(isAnalyser && audioContext){
player.audioAnalyser.active = false;
// this.globleAudioAnalyser.audioContext.suspend();
if(!isDestroy){
this.triggerListenerBroadcast(
player,
'onAudioAnalyserChange',
this.getAnalyserData(player, true)
)
}
}
}
getAnalyserData(player){
let isAnalyser = player.personalizedConfig?.analyser;
if(!isAnalyser){
return null
}
let { audioContext, analyser, analyserMediaElementSource, active} = player.audioAnalyser;
if(this.globleAudioAnalyser && active){
return {
player,
getAnalyserData:(count, averageCount=2)=>{
let length=analyser.frequencyBinCount * 44100 / audioContext.sampleRate|0;
let arr = new Uint8Array(length);
analyser.getByteFrequencyData(arr);
let l0 = 0;
let r0 = 0;
for(let i=0; i<arr.length; i++){
if(arr[i]>0 && l0==0){
l0 = i;
}
if(arr[length-i-1]>0 && r0==0){
r0 = length-i-1
}
if(l0!=0 && r0!=0){
break;
}
}
arr = arr.slice(l0,r0);
return this.splitArray(arr, count).map((chuck, index) => {
const step = Math.floor((chuck.length ?? 0) / averageCount);
let sum = 0;
for (let i = 0; i < chuck.length; i += step) {
sum += Math.abs(chuck[i]);
}
const average = sum / (chuck.length / step);
return Math.round(average);
});
}
}
}else{
return {
player,
getAnalyserData:(count)=>{
return new Uint8Array(count);
}
}
}
}
getOrCreatePlayer(url, options) {
if(!options && this.players[url]){
return {
url,
player: this.players[url],
id: this.players[url].id
}
}
const {
duration = 0,
clipStart = 0,
clipEnd = 0,
listeners,
personalizedConfig = {}
} = options;
const {
// 推荐
// onStateChange=()=>{},
onDurationChange=()=>{},
onBuffer=()=>{},
onLoadingStateChange=()=>{},
onPlayStateChange=()=>{},
onPositionChange=()=>{},
onAudioAnalyserChange=()=>{},
// 非必要 原生透传
onloadstart=()=>{},
onloadedmetadata=()=>{},
onloadeddata=()=>{},
oncanplay=()=>{},
oncanplaythrough=()=>{},
onplay=()=>{},
onplaying=()=>{},
onpause=()=>{},
onended=()=>{},
onerror=()=>{},
onprogress=()=>{},
ontimeupdate=()=>{},
} = listeners;
const id = this.getUuid();
const listenersCache = {
id,
// onStateChange,
onDurationChange,
onBuffer,
onLoadingStateChange,
onPlayStateChange,
onPositionChange,
onAudioAnalyserChange,
onloadstart,
onloadedmetadata,
onloadeddata,
oncanplay,
oncanplaythrough,
onplay,
onplaying,
onpause,
onended,
onerror,
onprogress,
ontimeupdate,
};
if (!this.players[url]) {
this.players[url]= {
id: id,
url: url,
isPlaying: false,
bufferedPosition: 0,
duration: duration,
currentTime: 0,
listeners: [listenersCache],
clipStart: clipStart,
clipEnd: clipEnd,
audioAnalyser: {
audioContext: null,
analyser: null,
fftSize: 2048,
analyserMediaElementSource: null,
},
personalizedConfig:{
...defaultConfig,
...personalizedConfig
}
};
const _clipStart = this.checkClipTime(this.players[url]).clipStart;
this.players[url].currentTime= _clipStart
this.triggerListenerBroadcast(
this.players[url],
'onPositionChange',
this.getPositionData(this.players[url])
)
}else{
this.players[url].listeners.push(listenersCache);
this.players[url].personalizedConfig={
...defaultConfig,
...this.players[url].personalizedConfig,
...personalizedConfig
}
this.triggerListenerBroadcast(
this.players[url],
'onPositionChange',
this.getPositionData(this.players[url])
)
}
return {
player: this.players[url],
id,
listenerId: id,
url
}
}
registerPlayUrl(url, options) { // 注册播放器
return this.getOrCreatePlayer(url, options);
}
releasePlayer(obj) { // 组件销毁时调用释放
const { player, uuid, url} = obj;
if (this.currentUrl == url) {
this.audio.pause();
this.audio.url = null;
this.currentUrl = null;
this.closeAudioAnalyser(this.players[url], true);
this.currentPlayer = null;
}
if(this.lastUrl==url){
this.lastUrl = null;
}
delete this.players[url];
}
setClip(url, from, to){
const player = this.players[url];
if(from >= 0 && to > from){
player.clipStart = from;
player.clipEnd = to;
}
const { clipStart } = this.checkClipTime(player)
player.currentTime = clipStart;
if(this.currentUrl === url){
this.audio.currentTime = clipStart;
}else{
this.triggerListenerBroadcast(
player,
'onPositionChange',
this.getPositionData(player)
)
}
}
checkNetworkStatus() {
window.addEventListener('online', ()=>{
if(this.audio.src){
this.audio.load();
if(this.players[this.audio.src]?.isPlaying){
this.audio.play();
}
}
});
}
async play(url, isInitSyncState=true) {
// console.log('play', url)
if (this.currentUrl !== url) {
this.lastUrl = this.currentUrl;
this.pause(this.currentUrl);
this.currentUrl = url;
this.audio.src = url;
if(navigator.onLine){
this.audio.load();
}
this.audio.currentTime = this.players[url].currentTime;
if(this.currentPlayer){
const { clipStart } = this.checkClipTime(this.currentPlayer)
const { canSeekNotCurrent, autoToStartIfNotCurrent } = this.currentPlayer.personalizedConfig;
if (autoToStartIfNotCurrent) {
this.currentPlayer.currentTime = clipStart;
this.triggerListenerBroadcast(
this.players[this.lastUrl],
'onPositionChange',
this.getPositionData(this.players[this.lastUrl])
)
}
await this.closeAudioAnalyser(this.currentPlayer);
}
this.currentPlayer = this.players[url];
}
this.audio.currentTime = this.currentPlayer.currentTime;
this.triggerGlobleListenerBroadcast('curPlayUrlChange', url, this.lastUrl)
try{
await this.audio.play();
this.currentPlayer.isPlaying = true;
this.openAudioAnalyser(this.currentPlayer);
if(isInitSyncState){
this.triggerListenerBroadcast(this.currentPlayer, 'onplay')
this.triggerListenerBroadcast(this.currentPlayer, 'onPlayStateChange', true)
}
}catch(e){
console.log("player Error",e);
this.audio.pause();
this.currentPlayer.isPlaying = false;
if(isInitSyncState){
this.triggerListenerBroadcast(this.currentPlayer, 'onpause')
this.triggerListenerBroadcast(this.currentPlayer, 'onPlayStateChange', false)
}
}
return this.currentPlayer.isPlaying;
}
pause(url, toStart) {
if (this.currentUrl == url && url!='') {
if (this.currentPlayer && this.currentPlayer.isPlaying) {
this.currentPlayer.isPlaying = false;
this.audio.pause();
if(toStart){
this.seek(url, 0);
}
this.triggerListenerBroadcast(this.currentPlayer, 'onpause')
this.triggerListenerBroadcast(this.currentPlayer, 'onPlayStateChange', false)
}
}else{
if(toStart){
this.seek(url, 0);
}
}
}
seek(url, progress) {
if(!url){
return;
}
if (this.currentUrl == url) {
const player =this.players[this.currentUrl];
const {clipStart, clipEnd } = this.checkClipTime(player);
const {duration} = player;
if(clipStart>=0 && clipEnd > clipStart){
const time = clipStart + progress * (clipEnd - clipStart);
this.audio.currentTime = time;
}else{
this.audio.currentTime = progress * duration;
}
}else{
const player = this.players[url];
const { canSeekNotCurrent, autoToStartIfNotCurrent } = player.personalizedConfig
const {clipStart, clipEnd } = this.checkClipTime(player);
const {duration} = player;
let time = duration * progress;
if(clipStart>=0 && clipEnd > clipStart){
time = clipStart + progress * (clipEnd - clipStart);
}
if(canSeekNotCurrent){
player.currentTime = time;
}else{
player.currentTime = clipStart;
}
this.triggerListenerBroadcast(
player,
'onPositionChange',
this.getPositionData(player,)
)
}
}
}
const globalAudioPlayer = new GlobalAudioPlayer();
export default globalAudioPlayer;
调用示例
arduino
// Example usage: 单位秒
// const renderData = reactive({
// url: props.url,
// startTime: '00:00',
// endTime: '00:00',
// bufferTime: '00:00',
// duration: props.duration,
// progress: 0,
// isPlaying: false,
// isLoading: false,
// });
// 初始化
// const curPlayerData = globalAudioPlayer.registerPlayUrl(renderData.url, {
// duration: props.duration ?? 0,
// clipStart: props.from,
// clipEnd: props.to,
// listeners: {
// onDurationChange({duration, durationTime,sourceDuration,sourceDurationTime}){
// renderData.duration = duration;
// renderData.endTime = durationTime;
// },
// onPlayStateChange(isPlaying){
// renderData.isPlaying = isPlaying;
// },
// onLoadingStateChange(isLoading){
// renderData.isLoading = isLoading;
// },
// onPositionChange: (obj)=>{
// const {progress, currentTime, endTime} = obj;
// if(!stateData.isChangeProgress){
// renderData.startTime = currentTime;
// renderData.progress = progress*100;
// }
// },
// }
// });
// 播放
// globalAudioPlayer.play(renderData.url, true);
// 暂停
// globalAudioPlayer.pause(renderData.url);
// 调整播放位置
// globalAudioPlayer.seek(renderData.url, renderData.progress/100);
// 调整播放区间
// globalAudioPlayer.setClip(renderData.url, startTime, endTime);
// 释放
// globalAudioPlayer.releasePlayer(curPlayerData);