Files
shoot-miniprograms/src/audioManager.js

602 lines
18 KiB
JavaScript
Raw Normal View History

2025-11-06 10:52:08 +08:00
export const audioFils = {
2025-10-29 18:07:42 +08:00
激光已校准:
"https://static.shelingxingqiu.com/attachment/2025-10-29/ddupaur1vdkyhzaqdc.mp3",
2025-09-18 09:28:04 +08:00
胜利: "https://static.shelingxingqiu.com/attachment/2025-09-17/dcuo9yjp0kt5msvmvd.mp3",
失败: "https://static.shelingxingqiu.com/attachment/2025-09-17/dcuo9yht2sdwhuqygy.mp3",
2025-09-15 11:23:22 +08:00
请射箭测试距离:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcuvj8avzqyw4hpq7t.mp3",
2025-09-15 11:23:22 +08:00
距离合格:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrda0amn5kqr4j.mp3",
2025-09-15 11:23:22 +08:00
距离不足:
2025-11-12 15:54:03 +08:00
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6hr2faw28t0ianh0.mp3",
2025-09-15 11:23:22 +08:00
轮到你了:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutzdrn4lxcpv8aqr.mp3",
2025-07-14 16:37:56 +08:00
第一轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutyyr9a7m1vz2w13.mp3",
2025-07-14 16:37:56 +08:00
第二轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutyyr9ldnfexjxtw.mp3",
2025-07-14 16:37:56 +08:00
第三轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutyyr97m4ipxaze4.mp3",
2025-07-14 16:37:56 +08:00
第四轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutyyr9x5addohlzf.mp3",
2025-07-14 16:37:56 +08:00
第五轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutyyr9d7lw2gebpv.mp3",
2025-07-14 16:37:56 +08:00
决金箭轮:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrd9zs4oi2kujv.mp3",
2025-08-28 19:34:24 +08:00
请蓝方射箭:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutzdrxcbe5ll46as.mp3",
2025-08-28 19:34:24 +08:00
请红方射箭:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutzdrl3re3dhlfjd.mp3",
2025-07-14 16:37:56 +08:00
中场休息:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrd9zdk1xyolst.mp3",
2025-07-14 16:37:56 +08:00
比赛结束:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutya59b6pu0ur4um.mp3",
2025-07-14 16:37:56 +08:00
比赛开始:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcuu5z3a3lumkutske.mp3",
2025-07-14 16:37:56 +08:00
请开始射击:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutzdrl5u0iromqhf.mp3",
2025-09-15 11:23:22 +08:00
射击无效:
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutya55ufiiw8oo55.mp3",
2025-07-14 16:37:56 +08:00
未上靶:
2025-11-12 20:40:00 +08:00
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6n45o3tsm1v4unam.mp3",
2025-07-14 16:37:56 +08:00
"1环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin1aq7gxjih5l.mp3",
2025-07-14 16:37:56 +08:00
"2环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin64tdgx2s4at.mp3",
2025-07-14 16:37:56 +08:00
"3环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinlmf87vt8z65.mp3",
2025-07-14 16:37:56 +08:00
"4环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinniv97sx0q9u.mp3",
2025-07-14 16:37:56 +08:00
"5环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin7j01kknpb7k.mp3",
2025-07-14 16:37:56 +08:00
"6环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin4syy1015rtq.mp3",
2025-07-14 16:37:56 +08:00
"7环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin3iz3dvmjdai.mp3",
2025-07-14 16:37:56 +08:00
"8环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinnjd42lhpfiw.mp3",
2025-07-14 16:37:56 +08:00
"9环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin69nj1xh7yfz.mp3",
2025-07-14 16:37:56 +08:00
"10环":
2025-09-18 09:28:04 +08:00
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinnvsx0tt7ksa.mp3",
2025-11-12 15:54:03 +08:00
向上调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf5pfvu3l8dhr.mp3",
向右上调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf45v88pirarr.mp3",
向右调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6elleqnhrenggxsb.mp3",
向右下调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6elleo6q16qctf6a.mp3",
向下调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellek2mu2cri2n9.mp3",
向左下调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf25yu1pt2k5r.mp3",
向左调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellen3zoalxcb06.mp3",
向左上调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf37a2iw6w4pu.mp3",
2025-11-13 21:04:48 +08:00
最后30秒:
"https://static.shelingxingqiu.com/attachment/2025-11-13/de7kzzllq0futwynso.mp3",
2025-11-14 15:51:45 +08:00
练习开始:
"https://static.shelingxingqiu.com/attachment/2025-11-14/de88w0lmmt43nnfmoi.mp3",
2025-07-14 16:37:56 +08:00
};
2025-09-18 10:01:10 +08:00
// 版本控制日志函数
function debugLog(...args) {
// 获取当前环境信息
const accountInfo = uni.getAccountInfoSync();
const envVersion = accountInfo.miniProgram.envVersion;
2025-10-29 18:07:42 +08:00
2025-09-18 10:01:10 +08:00
// 只在体验版打印日志,正式版(release)和开发版(develop)不打印
2025-10-29 18:07:42 +08:00
if (envVersion === "trial") {
2025-09-18 10:01:10 +08:00
console.log(...args);
}
}
2025-07-14 16:37:56 +08:00
class AudioManager {
constructor() {
this.audioMap = new Map();
2025-09-18 09:28:04 +08:00
this.currentPlayingKey = null;
this.retryCount = new Map();
this.maxRetries = 3;
2025-11-05 18:30:33 +08:00
// 显式授权播放标记,防止 iOS 在设置 src 后误播
this.allowPlayMap = new Map();
2025-10-29 18:07:42 +08:00
2025-09-18 09:28:04 +08:00
// 串行加载相关属性
this.audioKeys = [];
this.currentLoadingIndex = 0;
this.isLoading = false;
this.loadingPromise = null;
2025-10-29 18:07:42 +08:00
2025-11-12 11:39:17 +08:00
// 连续播放队列相关属性
this.sequenceQueue = [];
this.sequenceIndex = 0;
this.isSequenceRunning = false;
2025-11-14 09:25:24 +08:00
// 防重复播放保护
this.lastPlayKey = null;
this.lastPlayAt = 0;
2025-11-12 16:14:48 +08:00
// 静音开关
this.isMuted = false;
2025-11-06 17:38:34 +08:00
// 网络状态相关
this.networkOnline = true;
this.pendingPlayKey = null;
2025-11-25 15:02:50 +08:00
// 新增:就绪状态映射
this.readyMap = new Map();
2025-11-06 17:38:34 +08:00
try {
uni.onNetworkStatusChange(({ isConnected }) => {
this.networkOnline = !!isConnected;
if (this.networkOnline) {
this.onNetworkRestored();
} else {
this.onNetworkLost();
}
});
} catch (_) {}
2025-08-29 10:41:25 +08:00
this.initAudios();
}
// 初始化音频
initAudios() {
2025-09-18 09:28:04 +08:00
if (this.isLoading) {
2025-09-18 10:01:10 +08:00
debugLog("音频正在加载中,跳过重复初始化");
2025-09-18 09:28:04 +08:00
return this.loadingPromise;
}
2025-09-18 10:01:10 +08:00
debugLog("开始串行加载音频...");
2025-09-18 09:28:04 +08:00
this.isLoading = true;
this.audioKeys = Object.keys(audioFils);
this.currentLoadingIndex = 0;
2025-10-29 18:07:42 +08:00
2025-09-18 09:28:04 +08:00
this.loadingPromise = new Promise((resolve) => {
this.loadNextAudio(resolve);
});
2025-10-29 18:07:42 +08:00
2025-09-18 09:28:04 +08:00
return this.loadingPromise;
}
// 串行加载下一个音频
loadNextAudio(onComplete) {
if (this.currentLoadingIndex >= this.audioKeys.length) {
2025-09-18 10:01:10 +08:00
debugLog("所有音频加载完成");
2025-09-18 09:28:04 +08:00
this.isLoading = false;
if (onComplete) onComplete();
return;
}
const key = this.audioKeys[this.currentLoadingIndex];
2025-10-29 18:07:42 +08:00
debugLog(
`开始加载音频 ${this.currentLoadingIndex + 1}/${
this.audioKeys.length
}: ${key}`
);
2025-09-18 09:28:04 +08:00
this.createAudio(key, () => {
this.currentLoadingIndex++;
setTimeout(() => {
this.loadNextAudio(onComplete);
}, 100);
2025-07-14 16:37:56 +08:00
});
}
2025-08-29 10:41:25 +08:00
// 创建单个音频实例
2025-09-18 09:28:04 +08:00
createAudio(key, callback) {
const src = audioFils[key];
2025-08-29 10:41:25 +08:00
const audio = uni.createInnerAudioContext();
audio.autoplay = false;
2025-11-05 18:30:33 +08:00
audio.src = src;
2025-11-12 16:14:48 +08:00
// 初始化音量(支持的平台用 volumeH5 也可用 muted 作为兜底)
try {
if (typeof audio.volume === "number") {
audio.volume = this.isMuted ? 0 : 1;
} else if (typeof audio.muted !== "undefined") {
audio.muted = this.isMuted;
}
} catch (_) {}
2025-11-05 18:30:33 +08:00
// 初始化为不允许播放,只有显式 play() 才允许
this.allowPlayMap.set(key, false);
// 防止 iOS 误播:非授权播放立刻停止
audio.onPlay(() => {
if (!this.allowPlayMap.get(key)) {
try {
audio.stop();
} catch (_) {}
}
});
2025-08-29 10:41:25 +08:00
2025-09-18 09:28:04 +08:00
// 设置加载超时
const loadTimeout = setTimeout(() => {
2025-09-18 10:01:10 +08:00
debugLog(`音频 ${key} 加载超时`);
2025-09-18 09:28:04 +08:00
audio.destroy();
if (callback) callback();
}, 10000);
2025-08-29 10:41:25 +08:00
// 监听加载状态
audio.onCanplay(() => {
2025-11-06 14:06:37 +08:00
// 预加载阶段:仅在未授权情况下暂停,避免用户刚点击播放被打断
if (!this.allowPlayMap.get(key)) {
try {
audio.pause();
} catch (_) {}
}
2025-09-18 09:28:04 +08:00
clearTimeout(loadTimeout);
2025-11-25 15:02:50 +08:00
// 标记为已就绪
this.readyMap.set(key, true);
2025-09-18 10:01:10 +08:00
debugLog(`音频 ${key} 已加载完成`);
2025-11-06 10:52:08 +08:00
uni.$emit("audioLoaded", key);
const loadedAudioKeys = uni.getStorageSync("loadedAudioKeys") || {};
loadedAudioKeys[key] = true;
uni.setStorageSync("loadedAudioKeys", loadedAudioKeys);
2025-08-29 10:41:25 +08:00
this.retryCount.set(key, 0);
2025-09-18 09:28:04 +08:00
if (callback) callback();
2025-08-29 10:41:25 +08:00
});
audio.onError((res) => {
2025-09-18 09:28:04 +08:00
clearTimeout(loadTimeout);
2025-09-18 10:01:10 +08:00
debugLog(`音频 ${key} 加载失败:`, res.errMsg);
2025-11-05 18:30:33 +08:00
this.allowPlayMap.set(key, false);
2025-11-25 15:02:50 +08:00
// 标记为未就绪
this.readyMap.set(key, false);
2025-08-29 10:41:25 +08:00
this.handleAudioError(key);
2025-09-18 09:28:04 +08:00
if (callback) callback();
2025-08-29 10:41:25 +08:00
});
// 监听播放结束事件
audio.onEnded(() => {
if (this.currentPlayingKey === key) {
this.currentPlayingKey = null;
}
2025-11-05 18:30:33 +08:00
this.allowPlayMap.set(key, false);
2025-11-12 11:39:17 +08:00
// 触发连续播放队列的衔接
this.onAudioEnded(key);
2025-08-29 10:41:25 +08:00
});
// 监听播放停止事件
audio.onStop(() => {
if (this.currentPlayingKey === key) {
this.currentPlayingKey = null;
}
2025-11-05 18:30:33 +08:00
this.allowPlayMap.set(key, false);
2025-08-29 10:41:25 +08:00
});
this.audioMap.set(key, audio);
if (!this.retryCount.has(key)) {
this.retryCount.set(key, 0);
}
}
// 处理音频加载错误
handleAudioError(key) {
2025-11-06 17:38:34 +08:00
// 网络不可用时不重试,等重连后统一重建
if (!this.networkOnline) {
debugLog(`网络不可用,暂不重试音频: ${key}`);
return;
}
2025-08-29 10:41:25 +08:00
const currentRetries = this.retryCount.get(key) || 0;
2025-09-15 11:23:22 +08:00
2025-08-29 10:41:25 +08:00
if (currentRetries < this.maxRetries) {
this.retryCount.set(key, currentRetries + 1);
2025-09-18 10:01:10 +08:00
debugLog(`音频 ${key} 开始第 ${currentRetries + 1} 次重试...`);
2025-10-29 18:07:42 +08:00
2025-08-29 10:41:25 +08:00
setTimeout(() => {
this.retryLoadAudio(key);
2025-09-18 09:28:04 +08:00
}, 1000);
2025-08-29 10:41:25 +08:00
} else {
2025-10-29 18:07:42 +08:00
console.error(
`音频 ${key} 重试 ${this.maxRetries} 次后仍然失败,停止重试`
);
2025-09-18 09:28:04 +08:00
const failedAudio = this.audioMap.get(key);
if (failedAudio) {
failedAudio.destroy();
this.audioMap.delete(key);
}
2025-08-29 10:41:25 +08:00
}
}
// 重新加载音频
retryLoadAudio(key) {
2025-11-06 17:38:34 +08:00
if (!this.networkOnline) {
debugLog(`网络不可用,稍后再重载音频: ${key}`);
return;
}
2025-08-29 10:41:25 +08:00
const oldAudio = this.audioMap.get(key);
if (oldAudio) {
oldAudio.destroy();
}
this.createAudio(key);
}
2025-11-12 11:39:17 +08:00
// 播放指定音频或音频数组(数组则按顺序连续播放)
2025-11-13 21:23:45 +08:00
play(input, interrupt = true) {
// 统一规范化为队列
let queue = [];
2025-11-12 11:39:17 +08:00
if (Array.isArray(input)) {
2025-11-13 21:23:45 +08:00
queue = input.filter((k) => !!audioFils[k]);
} else if (typeof input === "string") {
queue = !!audioFils[input] ? [input] : [];
} else {
debugLog("play 参数类型无效,仅支持字符串或字符串数组");
return;
}
if (queue.length === 0) {
debugLog("连续播放队列为空或无效");
return;
}
if (interrupt) {
// 立即打断并启动新的播放序列
this.stopAll();
this.isSequenceRunning = false;
this.sequenceQueue = [];
this.sequenceIndex = 0;
2025-11-12 11:39:17 +08:00
this.sequenceQueue = queue;
this.sequenceIndex = 0;
this.isSequenceRunning = true;
this._playSingle(queue[0], false);
2025-11-13 21:23:45 +08:00
return;
}
// 不打断当前播放:把新的队列加入到序列中,等待当前播放结束后衔接
if (this.currentPlayingKey) {
if (this.isSequenceRunning) {
// 已有序列在跑:直接追加
this.sequenceQueue = this.sequenceQueue.concat(queue);
} else {
// 没有序列但当前有正在播放的:以当前为序列的起点
this.isSequenceRunning = true;
this.sequenceQueue = [this.currentPlayingKey].concat(queue);
this.sequenceIndex = 0;
// 不触发 _playSingle等待当前音频自然结束后由 onAudioEnded 接管
}
2025-11-12 11:39:17 +08:00
} else {
2025-11-13 21:23:45 +08:00
// 当前没有播放:直接启动新的序列
this.sequenceQueue = queue;
this.sequenceIndex = 0;
this.isSequenceRunning = true;
this._playSingle(queue[0], false);
2025-11-12 11:39:17 +08:00
}
}
// 内部方法:播放单个 key
_playSingle(key, forceStopAll = false) {
2025-11-14 09:25:24 +08:00
// 200ms 内的同 key 重复播放直接忽略,避免“比比赛开始”这类重复首音
const now = Date.now();
if (this.lastPlayKey === key && now - this.lastPlayAt < 250) {
debugLog(`忽略快速重复播放: ${key}`);
return;
}
2025-11-06 17:38:34 +08:00
if (!this.networkOnline) {
2025-11-13 16:29:21 +08:00
const audio = this.audioMap.get(key);
const isReady = this.readyMap && this.readyMap.get(key);
// 离线但已就绪:允许直接播放;未就绪则记录等待重连
if (!audio || !isReady) {
this.pendingPlayKey = key;
debugLog(`网络不可用,记录播放: ${key}`);
return;
}
2025-11-06 17:38:34 +08:00
}
2025-11-12 11:39:17 +08:00
if (forceStopAll) {
this.stopAll();
} else if (this.currentPlayingKey && this.currentPlayingKey !== key) {
2025-08-27 18:23:59 +08:00
this.stop(this.currentPlayingKey);
2025-11-14 09:25:24 +08:00
} else if (this.currentPlayingKey === key) {
// 同一音频正在播放:不重启,避免听到重复开头
return;
2025-08-27 18:23:59 +08:00
}
2025-07-14 16:37:56 +08:00
const audio = this.audioMap.get(key);
2025-08-27 18:23:59 +08:00
if (audio) {
2025-11-12 16:14:48 +08:00
// 播放前确保遵循当前静音状态
try {
if (typeof audio.volume === "number") {
audio.volume = this.isMuted ? 0 : 1;
} else if (typeof audio.muted !== "undefined") {
audio.muted = this.isMuted;
}
} catch (_) {}
2025-11-06 11:29:08 +08:00
// 同一音频:避免 stop() 触发 onStop 清除授权,使用 pause()+seek(0)
try {
audio.pause();
} catch (_) {}
try {
if (typeof audio.seek === "function") {
audio.seek(0);
} else {
audio.startTime = 0;
}
} catch (_) {
audio.startTime = 0;
}
2025-11-05 18:30:33 +08:00
// 显式授权播放并立即播放
this.allowPlayMap.set(key, true);
2025-11-06 11:29:08 +08:00
2025-09-18 09:28:04 +08:00
audio.play();
this.currentPlayingKey = key;
2025-11-14 09:25:24 +08:00
this.lastPlayKey = key;
this.lastPlayAt = Date.now();
2025-09-18 09:28:04 +08:00
} else {
2025-09-18 10:01:10 +08:00
debugLog(`音频 ${key} 不存在,尝试重新加载...`);
2025-09-18 09:28:04 +08:00
this.reloadAudio(key);
2025-08-27 18:23:59 +08:00
}
2025-07-14 16:37:56 +08:00
}
2025-11-12 11:39:17 +08:00
// 连续播放:在某个音频结束后,若处于队列播放状态则继续下一个
onAudioEnded(key) {
if (!this.isSequenceRunning) return;
const currentKey = this.sequenceQueue[this.sequenceIndex];
if (currentKey !== key) return;
const nextIndex = this.sequenceIndex + 1;
if (nextIndex < this.sequenceQueue.length) {
this.sequenceIndex = nextIndex;
const nextKey = this.sequenceQueue[nextIndex];
this._playSingle(nextKey, false);
} else {
// 队列播放完成
this.isSequenceRunning = false;
this.sequenceQueue = [];
this.sequenceIndex = 0;
}
}
2025-07-14 16:37:56 +08:00
// 停止指定音频
stop(key) {
const audio = this.audioMap.get(key);
2025-08-27 18:23:59 +08:00
if (audio) {
audio.stop();
2025-11-05 18:30:33 +08:00
this.allowPlayMap.set(key, false);
2025-08-27 18:23:59 +08:00
if (this.currentPlayingKey === key) {
this.currentPlayingKey = null;
}
}
2025-07-14 16:37:56 +08:00
}
2025-11-06 14:06:37 +08:00
// 停止所有音频
stopAll() {
for (const [k, audio] of this.audioMap.entries()) {
try {
audio.stop();
} catch (_) {}
this.allowPlayMap.set(k, false);
}
this.currentPlayingKey = null;
}
// 销毁所有音频实例并清理状态
destroyAll() {
for (const [k, audio] of this.audioMap.entries()) {
try {
audio.destroy();
} catch (_) {}
this.allowPlayMap.delete(k);
this.retryCount.delete(k);
this.audioMap.delete(k);
2025-11-25 15:02:50 +08:00
this.readyMap.delete(k);
2025-11-06 14:06:37 +08:00
}
this.audioKeys = [];
this.currentLoadingIndex = 0;
this.isLoading = false;
this.loadingPromise = null;
this.currentPlayingKey = null;
}
2025-11-06 17:38:34 +08:00
// 断网回调:停止当前播放,避免误状态
onNetworkLost() {
try {
this.stopAll();
} catch (_) {}
}
2025-11-13 16:29:21 +08:00
// 重连回调:重建全部音频后,重放上一次的播放
2025-11-06 17:38:34 +08:00
onNetworkRestored() {
2025-11-13 16:29:21 +08:00
// 网络恢复后,仅继续加载未就绪或缺失的音频,已就绪的不动,保证离线可播的缓存不被重置
const keys = Object.keys(audioFils);
const needLoad = keys.filter(
(k) => !this.readyMap.get(k) || !this.audioMap.has(k)
);
if (needLoad.length > 0) {
this.loadKeysSequentially(needLoad, () => {
if (this.pendingPlayKey) {
const pending = this.pendingPlayKey;
this.pendingPlayKey = null;
setTimeout(() => {
this.play(pending);
}, 20);
}
});
} else {
// 没有需要加载的音频,直接处理待播放
if (this.pendingPlayKey) {
const pending = this.pendingPlayKey;
this.pendingPlayKey = null;
setTimeout(() => {
this.play(pending);
}, 20);
}
2025-11-06 17:38:34 +08:00
}
}
// 重连后统一重建音频实例
reinitializeOnReconnect() {
this.destroyAll();
this.initAudios();
}
2025-11-13 16:29:21 +08:00
// 按自定义列表串行加载音频(避免并发过多)
loadKeysSequentially(keys, onComplete) {
let idx = 0;
const next = () => {
if (idx >= keys.length) {
if (onComplete) onComplete();
return;
}
const k = keys[idx++];
// 已存在但未就绪:重载;不存在:创建
if (this.audioMap.has(k)) {
this.retryLoadAudio(k);
} else {
this.createAudio(k, () => {
setTimeout(next, 100);
});
return; // createAudio 内部会触发 next
}
setTimeout(next, 100);
};
next();
}
2025-08-29 10:41:25 +08:00
// 手动重新加载指定音频
reloadAudio(key) {
if (audioFils[key]) {
2025-09-18 10:01:10 +08:00
debugLog(`手动重新加载音频: ${key}`);
2025-09-18 09:28:04 +08:00
this.retryCount.set(key, 0);
2025-08-29 10:41:25 +08:00
this.retryLoadAudio(key);
}
}
2025-11-12 16:14:48 +08:00
// 设置静音开关true 静音false 取消静音
setMuted(muted) {
this.isMuted = !!muted;
for (const audio of this.audioMap.values()) {
try {
if (typeof audio.volume === "number") {
audio.volume = this.isMuted ? 0 : 1;
} else if (typeof audio.muted !== "undefined") {
audio.muted = this.isMuted;
}
} catch (_) {}
}
debugLog(`静音状态已设置为: ${this.isMuted}`);
}
2025-11-25 15:02:50 +08:00
// 新增返回音频加载进度0~1
getLoadProgress() {
// 总数优先使用已初始化的 audioKeys未初始化则回退到 audioFils
const keys =
this.audioKeys && this.audioKeys.length > 0
? this.audioKeys
: Object.keys(audioFils);
const total = keys.length;
if (total === 0) return 0;
let loaded = 0;
for (const k of keys) {
if (this.readyMap.get(k)) loaded++;
}
return loaded / total;
}
2025-07-14 16:37:56 +08:00
}
// 导出单例
2025-11-25 15:02:50 +08:00
export default new AudioManager();