chicken_dy/Assets/WX-WASM-SDK/wechat-default/unity-sdk/audio.js

861 lines
32 KiB
JavaScript
Raw Normal View History

2022-08-01 03:47:37 +00:00
const audios = {};
import moduleHelper from "./module-helper";
const msg = 'InnerAudioContext does not exist!';
const localAudioMap = {};
const downloadingAudioMap = {};
const soundVolumeHandler = {};
const err = function(msg){GameGlobal.manager.printErr(msg)}
const funs = {
getFullUrl(v) {
if (!/^https?:\/\//.test(v)) {
const cdnPath = GameGlobal.manager.assetPath;
v = cdnPath.replace(/\/$/, '') + '/' + v.replace(/^\//, '').replace(/^Assets\//, '');
}
return encodeURI(v);
},
downloadMusic(src){
return new Promise((resolve,reject)=>{
wx.downloadFile({
url: src,
success(res) {
if (res.statusCode === 200 && res.tempFilePath ) {
localAudioMap[src] = res.tempFilePath;
wx.setStorage({
key:src,
data:res.tempFilePath
}).catch(e=>{});
resolve(true);
} else {
resolve(false);
}
},
fail(e) {
resolve(false);
err(e);
}
});
});
},
checkLocalFile(src){
return new Promise(async (resolve, reject)=>{
let path = localAudioMap[src];
if(!path){
try{
const res = await new Promise((subResolve,subReject)=>{
wx.getStorage({
key:src,
success:(r)=>{
subResolve(r);
},
fail:(e)=>{
subReject(e);
}
})
});
path = res.data;
localAudioMap[src] = path;
}catch (e){}
}
if(!path){
return resolve(false);
}
const fs = wx.getFileSystemManager();
fs.access({
path: path,
success() {
// 文件存在
resolve(true);
},
fail() {
// 文件不存在或其他错误
resolve(false);
}
});
})
},
handleDownloadEnd(src,succeeded){
if(!downloadingAudioMap[src]){
return;
}
while (downloadingAudioMap[src] && downloadingAudioMap[src].length>0){
const item = downloadingAudioMap[src].shift();
if(!succeeded){
item.reject();
}else{
item.resolve();
}
}
downloadingAudioMap[src] = null;
}
};
var WEBAudio = {
audioInstanceIdCounter: 0,
audioInstances: {},
audioContext: null,
audioWebEnabled: 0,
audioCache: [],
lOrientation: {x:0, y:0, z:0, xUp:0, yUp:0, zUp:0},
lPosition: {x:0, y:0, z:0}
};
export default {
WXCreateInnerAudioContext(src, loop, startTime, autoplay, volume, playbackRate, needDownload) {
const id = new Date().getTime().toString(32) + Math.random().toString(32);
audios[id] = wx.createInnerAudioContext();
playbackRate = 1; // 先强制为1android客户端有bug设为其他值的话
audios[id]._needDownload = needDownload;
audios[id]._src = src;
if (src) {
src = funs.getFullUrl(src);
funs.checkLocalFile(src).then(exist=>{
if(exist){
audios[id].src = localAudioMap[src];
funs.handleDownloadEnd(src,true);
}else if(needDownload){
const successFun = function(){
audios[id].src = localAudioMap[src];
};
const failFun = function(){
moduleHelper.send('OnAudioCallback', JSON.stringify({
callbackId: id,
errMsg: "onError"
}));
}
if(!downloadingAudioMap[src]) {
downloadingAudioMap[src] = [];
}
downloadingAudioMap[src].unshift({
resolve:successFun,reject:failFun
});
if(!downloadingAudioMap[src].isDownloading){
downloadingAudioMap[src].isDownloading = true;
funs.downloadMusic(src).then(succeeded=>{
funs.handleDownloadEnd(src,succeeded);
});
}
}else{
audios[id].src = src;
}
});
}
if (loop) {
audios[id].loop = true;
}
if (autoplay) {
audios[id].autoplay = true;
}
if (startTime > 0) {
audios[id].startTime = +startTime.toFixed(2);
}
if (volume !== 1) {
audios[id].volume = +volume.toFixed(2);
}
if (playbackRate !== 1) {
audios[id].playbackRate = +playbackRate.toFixed(2);
}
return id;
},
WXInnerAudioContextSetBool(id, k, v) {
if (audios[id]) {
audios[id][k] = Boolean(+v);
} else {
console.error(msg, id);
}
},
WXInnerAudioContextSetString(id, k, v) {
if (audios[id]) {
if (k === 'src') {
v = funs.getFullUrl(v);
if (localAudioMap[v]) {
v = localAudioMap[v];
}
}
audios[id][k] = v;
} else {
console.error(msg, id);
}
},
WXInnerAudioContextSetFloat(id, k, v) {
if (audios[id]) {
audios[id][k] = +v.toFixed(2);
} else {
console.error(msg, id);
}
},
WXInnerAudioContextGetFloat(id, k) {
if (audios[id]) {
return audios[id][k];
} else {
console.error(msg, id);
return 0;
}
},
WXInnerAudioContextGetBool(id, k) {
if (audios[id]) {
return audios[id][k];
} else {
console.error(msg, id);
return false;
}
},
WXInnerAudioContextPlay(id) {
if (audios[id]) {
audios[id].play();
} else {
console.error(msg, id);
}
},
WXInnerAudioContextPause(id) {
if (audios[id]) {
audios[id].pause();
} else {
console.error(msg, id);
}
},
WXInnerAudioContextStop(id) {
if (audios[id]) {
audios[id].stop();
} else {
console.error(msg, id);
}
},
WXInnerAudioContextDestroy(id) {
if (audios[id]) {
audios[id].destroy();
delete audios[id];
} else {
console.error(msg, id);
}
},
WXInnerAudioContextSeek(id, position) {
if (audios[id]) {
audios[id].seek(+position.toFixed(3));
} else {
console.error(msg, id);
}
},
WXInnerAudioContextAddListener(id, key) {
if (audios[id]) {
function AddListener(){
audios[id][key](function (e) {
moduleHelper.send('OnAudioCallback', JSON.stringify({
callbackId: id,
errMsg: key
}));
if (key === 'onError') {
console.error(e);
}
});
}
if(!audios[id].src && audios[id]._needDownload && audios[id]._src){
const src = funs.getFullUrl(audios[id]._src);
if(!downloadingAudioMap[src]){
downloadingAudioMap[src] = [];
}
downloadingAudioMap[src].push({
resolve:AddListener,
reject:()=>{}
});
}else{
AddListener();
}
} else {
console.error(msg, id);
}
},
WXInnerAudioContextRemoveListener(id, key) {
if (audios[id]) {
audios[id][key]();
} else {
console.error(msg, id);
}
},
WXPreDownloadAudios(paths, id) {
var list = paths.split(',');
Promise.all(list.map(v => {
const src = funs.getFullUrl(v);
return new Promise(async (resolve, reject) => {
if(!downloadingAudioMap[src]){
downloadingAudioMap[src] = [{
resolve,reject
}];
const exist = await funs.checkLocalFile(src);
if(exist){
funs.handleDownloadEnd(src,true);
return;
}
const succeeded = await funs.downloadMusic(src);
funs.handleDownloadEnd(src,succeeded);
}else{
downloadingAudioMap[src].push({
resolve,reject
});
}
})
})).then(() => {
moduleHelper.send('WXPreDownloadAudiosCallback', JSON.stringify({
callbackId: id.toString(),
errMsg: "0"
}));
}).catch(e => {
moduleHelper.send('WXPreDownloadAudiosCallback', JSON.stringify({
callbackId: id.toString(),
errMsg: "1"
}));
})
},
//-------------------Unity Audio适配--------------------
_JS_Sound_Create_Channel(callback, userData) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = {
gain: WEBAudio.audioContext.createGain(),
panner: WEBAudio.audioContext.createPanner(),
threeD: false,
playUrl: function (startTime, url, startOffset) {
try {
this.setup(url);
var chan = this;
this.source.onended = function () {
chan.disconnectSource();
if (callback) GameGlobal.unityNamespace.Module.dynCall_vi(callback, [userData]);
};
this.source.start(startTime, startOffset);
this.source.playbackStartTime =
startTime - startOffset / this.source.playbackRate.value;
} catch (e) {
err("playUrl error. Exception: " + e);
}
},
playBuffer: function (startTime, buffer, startOffset) {
try {
this.setup();
this.source.buffer = buffer;
var chan = this;
this.source.onended = function () {
chan.disconnectSource();
if (callback) GameGlobal.unityNamespace.Module.dynCall_vi(callback, [userData]);
};
this.source.start(startTime, startOffset);
this.source.playbackStartTime =
startTime - startOffset / this.source.playbackRate.value;
} catch (e) {
err("playUrl error. Exception: " + e);
}
},
disconnectSource: function () {
if (this.source && !this.source.isPausedMockNode) {
this.source.onended = null;
this.source.disconnect();
if (this.source.mediaElement) {
var url = this.source.mediaElement.src;
this.source.mediaElement.pause();
this.source.mediaElement.src = "";
delete this.source.mediaElement;
URL.revokeObjectURL(url);
}
delete this.source;
}
},
stop: function (delay) {
if (channel.source && channel.source.buffer) {
try {
channel.source.stop(WEBAudio.audioContext.currentTime + delay);
} catch (e) {}
if (delay == 0) {
channel.disconnectSource();
}
}
},
pause: function () {
var s = this.source;
if (!s) return;
if (s.mediaElement) {
this.pauseMediaElement();
return;
}
var pausedSource = {
isPausedMockNode: true,
loop: s.loop,
loopStart: s.loopStart,
loopEnd: s.loopEnd,
buffer: s.buffer,
url: s.mediaElement ? s.mediaElement.src : null,
playbackRate: s.playbackRate.value,
playbackPausedAtPosition: s.estimatePlaybackPosition(),
setPitch: function (v) {
this.playbackRate = v;
},
};
this.stop(0);
this.disconnectSource();
this.source = pausedSource;
},
resume: function () {
var pausedSource = this.source;
if (pausedSource && pausedSource.mediaElement) {
pausedSource.start();
return;
}
if (!pausedSource || !pausedSource.isPausedMockNode) return;
delete this.source;
if (pausedSource.url) {
this.playUrl(
WEBAudio.audioContext.currentTime -
Math.min(0, pausedSource.playbackPausedAtPosition),
pausedSource.url,
Math.max(0, pausedSource.playbackPausedAtPosition)
);
} else {
this.playBuffer(
WEBAudio.audioContext.currentTime -
Math.min(0, pausedSource.playbackPausedAtPosition),
pausedSource.buffer,
Math.max(0, pausedSource.playbackPausedAtPosition)
);
}
this.source.loop = pausedSource.loop;
this.source.loopStart = pausedSource.loopStart;
this.source.loopEnd = pausedSource.loopEnd;
this.source.setPitch(pausedSource.playbackRate);
},
setup: function (url) {
if (this.source && !this.source.isPausedMockNode) return;
if (!url) {
this.source = WEBAudio.audioContext.createBufferSource();
} else {
this.mediaElement = WEBAudio.audioCache.length ?
WEBAudio.audioCache.pop() :
new Audio();
this.mediaElement.preload = "metadata";
this.mediaElement.src = url;
this.source = WEBAudio.audioContext.createMediaElementSource(
this.mediaElement
);
this.source.playbackRate = {};
var source = this.source;
Object.defineProperty(this.source, "loop", {
get: function () {
return source.mediaElement.loop;
},
set: function (v) {
source.mediaElement.loop = v;
},
});
Object.defineProperty(this.source.playbackRate, "value", {
get: function () {
return source.mediaElement.playbackRate;
},
set: function (v) {
source.mediaElement.playbackRate = v;
},
});
Object.defineProperty(this.source, "currentTime", {
get: function () {
return source.mediaElement.currentTime;
},
set: function (v) {
source.mediaElement.currentTime = v;
},
});
Object.defineProperty(this.source, "mute", {
get: function () {
return source.mediaElement.mute;
},
set: function (v) {
source.mediaElement.mute = v;
},
});
var self = this;
this.playPromise = null;
this.pauseRequested = false;
this.pauseMediaElement = function () {
if (self.playPromise) {
self.pauseRequested = true;
} else {
source.mediaElement.pause();
}
};
var _startPlayback = function (offset) {
if (self.playPromise) {
self.pauseRequested = false;
return;
}
source.mediaElement.currentTime = offset;
self.playPromise = source.mediaElement.play();
if (self.playPromise) {
self.playPromise.then(function () {
if (self.pauseRequested) {
source.mediaElement.pause();
self.pauseRequested = false;
}
self.playPromise = null;
});
}
};
this.source.start = function (startTime, offset) {
var startDelayThresholdMS = 4;
var startDelayMS =
(startTime - WEBAudio.audioContext.currentTime) * 1e3;
if (startDelayMS > startDelayThresholdMS) {
setTimeout(function () {
_startPlayback(offset);
}, startDelayMS);
} else {
_startPlayback(offset);
}
};
this.source.stop = function () {
self.pauseMediaElement();
};
}
this.source.estimatePlaybackPosition = function () {
var t =
(WEBAudio.audioContext.currentTime - this.playbackStartTime) *
this.playbackRate.value;
if (this.loop && t >= this.loopStart) {
t =
((t - this.loopStart) % (this.loopEnd - this.loopStart)) +
this.loopStart;
}
return t;
};
this.source.setPitch = function (newPitch) {
var curPosition = this.estimatePlaybackPosition();
if (curPosition >= 0) {
this.playbackStartTime =
WEBAudio.audioContext.currentTime - curPosition / newPitch;
}
this.playbackRate.value = newPitch;
};
this.setupPanning();
},
setupPanning: function () {
if (this.source.isPausedMockNode) return;
this.source.disconnect();
if (this.threeD) {
this.source.connect(this.panner);
this.panner.connect(this.gain);
} else {
this.panner.disconnect();
this.source.connect(this.gain);
}
},
};
channel.panner.rolloffFactor = 0;
channel.gain.connect(WEBAudio.audioContext.destination);
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = channel;
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_GetLength(bufferInstance) {
if (WEBAudio.audioWebEnabled == 0) return 0;
var sound = WEBAudio.audioInstances[bufferInstance];
if (sound.buffer) {
var sampleRateRatio = 44100 / sound.buffer.sampleRate;
return sound.buffer.length * sampleRateRatio;
}
return sound.mediaElement.duration * 44100;
},
_JS_Sound_GetLoadState(bufferInstance) {
if (WEBAudio.audioWebEnabled == 0) return 2;
var sound = WEBAudio.audioInstances[bufferInstance];
if (sound.error) return 2;
if (sound.buffer || sound.url) return 0;
return 1;
},
_JS_Sound_Init() {
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
if (window.AudioContext) {
WEBAudio.audioContext = new AudioContext();
}
if (wx && wx.createWebAudioContext) {
WEBAudio.audioContext = wx.createWebAudioContext();
console.log("use wx WebAudio");
}
if (!WEBAudio.audioContext) {
err('Minigame Web Audio API not suppoted')
return
}
var tryToResumeAudioContext = function () {
if (WEBAudio.audioContext.state === "suspended") {
WEBAudio.audioContext.resume();
}
else clearInterval(resumeInterval);
};
// var resumeInterval = setInterval(tryToResumeAudioContext, 400);
WEBAudio.audioWebEnabled = 1;
wx.onShow((result) => {WEBAudio.audioContext.resume()});
} catch (e) {
err("Web Audio API is not supported in this browser");
}
},
_JS_Sound_Load(ptr, length, decompress) {
if (WEBAudio.audioWebEnabled == 0) return 0;
var sound = {
buffer: null,
error: false
};
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = sound;
var audioData = GameGlobal.unityNamespace.Module.HEAPU8.buffer.slice(ptr, ptr + length);
WEBAudio.audioContext.decodeAudioData(
audioData,
function (buffer) {
sound.buffer = buffer;
},
function (error) {
sound.error = true;
console.log("Decode error: " + error);
}
);
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_Load_PCM(channels, length, sampleRate, ptr) {
if (WEBAudio.audioWebEnabled == 0) return 0;
var sound = {
buffer: WEBAudio.audioContext.createBuffer(channels, length, sampleRate),
error: false,
};
for (var i = 0; i < channels; i++) {
var offs = (ptr >> 2) + length * i;
var buffer = sound.buffer;
var copyToChannel =
buffer["copyToChannel"] ||
function (source, channelNumber, startInChannel) {
var clipped = source.subarray(
0,
Math.min(source.length, this.length - (startInChannel | 0))
);
this.getChannelData(channelNumber | 0).set(clipped, startInChannel | 0);
};
copyToChannel.apply(buffer, [GameGlobal.unityNamespace.Module.HEAPF32.subarray(offs, offs + length), i, 0]);
}
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = sound;
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_Play(bufferInstance, channelInstance, offset, delay) {
WXWASMSDK._JS_Sound_Stop(channelInstance, 0);
if (WEBAudio.audioWebEnabled == 0) return;
var sound = WEBAudio.audioInstances[bufferInstance];
var channel = WEBAudio.audioInstances[channelInstance];
if (sound.url) {
try {
channel.playUrl(
WEBAudio.audioContext.currentTime + delay,
sound.url,
offset
);
} catch (e) {
err("playUrl error. Exception: " + e);
}
} else if (sound.buffer) {
try {
channel.playBuffer(
WEBAudio.audioContext.currentTime + delay,
sound.buffer,
offset
);
} catch (e) {
err("playBuffer error. Exception: " + e);
}
} else console.log("Trying to play sound which is not loaded.");
},
_JS_Sound_ReleaseInstance(instance) {
delete WEBAudio.audioInstances[instance];
},
_JS_Sound_ResumeIfNeeded() {
if (WEBAudio.audioWebEnabled == 0) return;
if (WEBAudio.audioContext.state === "suspended")
WEBAudio.audioContext.resume();
},
_JS_Sound_Set3D(channelInstance, threeD) {
var channel = WEBAudio.audioInstances[channelInstance];
if (channel.threeD != threeD) {
channel.threeD = threeD;
if (!channel.source) {
channel.setup();
}
channel.setupPanning();
}
},
_JS_Sound_SetListenerOrientation(x, y, z, xUp, yUp, zUp) {
if (WEBAudio.audioWebEnabled == 0) return;
x = x > 0 ? 0 : x;
y = y > 0 ? 0 : y;
z = z > 0 ? 0 : z;
xUp = xUp < 0 ? 0 : xUp;
yUp = yUp < 0 ? 0 : yUp;
zUp = zUp < 0 ? 0 : zUp;
if (x==WEBAudio.lOrientation.x && y==WEBAudio.lOrientation.y && z==WEBAudio.lOrientation.z && xUp==WEBAudio.lOrientation.xUp && yUp==WEBAudio.lOrientation.yUp && zUp==WEBAudio.lOrientation.zUp){return;}
WEBAudio.lOrientation.x = x;
WEBAudio.lOrientation.y = y;
WEBAudio.lOrientation.z = z;
WEBAudio.lOrientation.xUp = xUp;
WEBAudio.lOrientation.yUp = yUp;
WEBAudio.lOrientation.zUp = zUp;
if (WEBAudio.audioContext.listener.forwardX) {
WEBAudio.audioContext.listener.forwardX.setValueAtTime(
-x,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.forwardY.setValueAtTime(
-y,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.forwardZ.setValueAtTime(
-z,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.upX.setValueAtTime(
xUp,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.upY.setValueAtTime(
yUp,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.upZ.setValueAtTime(
zUp,
WEBAudio.audioContext.currentTime
);
} else {
WEBAudio.audioContext.listener.setOrientation(-x, -y, -z, xUp, yUp, zUp);
}
},
_JS_Sound_SetListenerPosition(x, y, z) {
if (WEBAudio.audioWebEnabled == 0) return;
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;
z = z < 0 ? 0 : z;
if (x==WEBAudio.lPosition.x && y==WEBAudio.lPosition.y && z==WEBAudio.lPosition.z){return;}
WEBAudio.lPosition.x = x;
WEBAudio.lPosition.y = y;
WEBAudio.lPosition.z = z;
if (WEBAudio.audioContext.listener.positionX) {
WEBAudio.audioContext.listener.positionX.setValueAtTime(
x,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.positionY.setValueAtTime(
y,
WEBAudio.audioContext.currentTime
);
WEBAudio.audioContext.listener.positionZ.setValueAtTime(
z,
WEBAudio.audioContext.currentTime
);
} else {
WEBAudio.audioContext.listener.setPosition(x, y, z);
}
},
_JS_Sound_SetLoop(channelInstance, loop) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = WEBAudio.audioInstances[channelInstance];
if (!channel.source) {
channel.setup();
}
channel.source.loop = loop > 0 ? true : false;
},
_JS_Sound_SetLoopPoints(channelInstance, loopStart, loopEnd) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = WEBAudio.audioInstances[channelInstance];
if (!channel.source) {
channel.setup();
}
channel.source.loopStart = loopStart;
channel.source.loopEnd = loopEnd;
},
_JS_Sound_SetPaused(channelInstance, paused) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = WEBAudio.audioInstances[channelInstance];
var channelCurrentlyPaused = !channel.source || channel.source.isPausedMockNode;
if (paused != channelCurrentlyPaused) {
if (paused) channel.pause();
else channel.resume();
}
},
_JS_Sound_SetPitch(channelInstance, v) {
if (WEBAudio.audioWebEnabled == 0) return;
try {
WEBAudio.audioInstances[channelInstance].source.setPitch(v);
} catch (e) {
err("Invalid audio pitch " + v + " specified to WebAudio backend!");
}
},
_JS_Sound_SetPosition(channelInstance, x, y, z) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = WEBAudio.audioInstances[channelInstance];
if (channel.x != x || channel.y != y || channel.z != z) {
channel.panner.setPosition(x, y, z);
channel.x = x;
channel.y = y;
channel.z = z;
}
},
_JS_Sound_SetVolume(channelInstance, v) {
if (WEBAudio.audioWebEnabled == 0) return;
try {
let volume = Number(v.toFixed(2));
if (soundVolumeHandler[channelInstance] === volume) {return;}
soundVolumeHandler[channelInstance] = volume;
WEBAudio.audioInstances[channelInstance].gain.gain.setValueAtTime(
volume,
WEBAudio.audioContext.currentTime
);
} catch (e) {
err("Invalid audio volume " + v + " specified to WebAudio backend!");
}
},
_JS_Sound_Stop(channelInstance, delay) {
if (WEBAudio.audioWebEnabled == 0) return;
var channel = WEBAudio.audioInstances[channelInstance];
channel.stop(delay);
}
}
//声音被打断后自动帮用户恢复
const HandleInterruption = {
init() {
var InterruptList = {};
wx.onHide(function () {
for (var key in audios) {
if (!audios[key].paused) {
InterruptList[key] = true;
}
}
});
wx.onShow(function () {
for (var key in audios) {
if (audios[key].paused && InterruptList[key]) {
audios[key].play();
}
}
InterruptList = {};
});
wx.onAudioInterruptionBegin(function () {
for (var key in audios) {
if (!audios[key].paused) {
InterruptList[key] = true;
}
}
});
wx.onAudioInterruptionEnd(function () {
for (var key in audios) {
if (audios[key].paused && InterruptList[key]) {
audios[key].play();
}
}
InterruptList = {};
});
}
};
HandleInterruption.init();