861 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			861 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| 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; // 先强制为1,android客户端有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();
 |