diff --git a/pal/audio/minigame/player-web.ts b/pal/audio/minigame/player-web.ts index 869da1306cbc2a6c1d783f19c79ee12a65256254..56a07672a4444cf1a75611300122e0c3a481b4f1 100644 --- a/pal/audio/minigame/player-web.ts +++ b/pal/audio/minigame/player-web.ts @@ -25,6 +25,7 @@ import { minigame } from 'pal/minigame'; import { systemInfo } from 'pal/system-info'; import { clamp01 } from '../../../cocos/core'; +import * as debug from '../../../cocos/core/platform/debug'; import { EventTarget } from '../../../cocos/core/event'; import { audioBufferManager } from '../audio-buffer-manager'; import AudioTimer from '../audio-timer'; @@ -133,7 +134,7 @@ export class AudioPlayerWeb implements OperationQueueable { this._state = AudioState.INTERRUPTED; this._readyToHandleOnShow = true; this._eventTarget.emit(AudioEvent.INTERRUPTION_BEGIN); - }).catch((e) => {}); + }).catch((e) => { debug.warn('_onInterruptedBegin error', e); }); } } private _onInterruptedEnd (): void { @@ -145,7 +146,7 @@ export class AudioPlayerWeb implements OperationQueueable { if (this._state === AudioState.INTERRUPTED) { this.play().then(() => { this._eventTarget.emit(AudioEvent.INTERRUPTION_END); - }).catch((e) => {}); + }).catch((e) => { debug.warn('_onInterruptedEnd error', e); }); } this._readyToHandleOnShow = false; } @@ -153,7 +154,7 @@ export class AudioPlayerWeb implements OperationQueueable { return new Promise((resolve) => { AudioPlayerWeb.loadNative(url).then((audioBuffer) => { resolve(new AudioPlayerWeb(audioBuffer, url)); - }).catch((e) => {}); + }).catch((e) => { debug.warn('load error', url, e); }); }); } static loadNative (url: string): Promise { @@ -175,7 +176,7 @@ export class AudioPlayerWeb implements OperationQueueable { audioContext!.decodeAudioData(arrayBuffer).then((decodedAudioBuffer) => { audioBufferManager.addCache(url, decodedAudioBuffer); resolve(decodedAudioBuffer); - }).catch((e) => {}); + }).catch((e) => { debug.warn('loadNative error', url, e); }); }); }); } @@ -185,6 +186,7 @@ export class AudioPlayerWeb implements OperationQueueable { AudioPlayerWeb.loadNative(url).then((audioBuffer) => { // HACK: AudioPlayer should be a friend class in OneShotAudio const oneShotAudio = new (OneShotAudioWeb as any)(audioBuffer, volume, url); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument resolve(oneShotAudio); }).catch(reject); }); @@ -238,7 +240,7 @@ export class AudioPlayerWeb implements OperationQueueable { if (this._state === AudioState.PLAYING) { // one AudioBufferSourceNode can't start twice // need to create a new one to start from the offset - this._doPlay().then(resolve).catch((e) => {}); + this._doPlay().then(resolve).catch((e) => { debug.warn('seek error', e); }); } else { resolve(); } @@ -302,6 +304,8 @@ export class AudioPlayerWeb implements OperationQueueable { @enqueueOperation stop (): Promise { if (!this._sourceNode) { + this._audioTimer.stop(); + this._state = AudioState.STOPPED; return Promise.resolve(); } this._audioTimer.stop(); diff --git a/pal/audio/web/player-web.ts b/pal/audio/web/player-web.ts index 5d703d35d63fe25edef39f620d53ef4e473fa926..410e305d8d9408b36f953996d074c4bbee7640ec 100644 --- a/pal/audio/web/player-web.ts +++ b/pal/audio/web/player-web.ts @@ -26,6 +26,7 @@ import { EDITOR_NOT_IN_PREVIEW } from 'internal:constants'; import { AudioPCMDataView, AudioEvent, AudioState, AudioType } from '../type'; import { EventTarget } from '../../../cocos/core/event'; import { clamp01 } from '../../../cocos/core'; +import * as debug from '../../../cocos/core/platform/debug'; import { enqueueOperation, OperationInfo, OperationQueueable } from '../operation-queue'; import AudioTimer from '../audio-timer'; import { audioBufferManager } from '../audio-buffer-manager'; @@ -76,9 +77,10 @@ export class AudioContextAgent { resolve(audioBuffer); }, (err) => { // TODO: need to reject the error. + // eslint-disable-next-line no-console console.error('failed to load Web Audio', err); }); - promise?.catch((e) => {}); // Safari doesn't support the promise based decodeAudioData + promise?.catch((e) => { debug.warn('decodeAudioData error', e); }); // Safari doesn't support the promise based decodeAudioData }); } @@ -93,7 +95,7 @@ export class AudioContextAgent { resolve(); return; } - context.resume().catch((e) => {}); + context.resume().catch((e) => { debug.warn('runContext error', e); }); if (context.state === 'running') { resolve(); return; @@ -106,7 +108,7 @@ export class AudioContextAgent { canvas?.removeEventListener('touchend', onGesture, { capture: true }); canvas?.removeEventListener('mouseup', onGesture, { capture: true }); resolve(); - }).catch((e) => {}); + }).catch((e) => { debug.warn('onGesture resume error', e); }); }; canvas?.addEventListener('touchend', onGesture, { capture: true }); canvas?.addEventListener('mouseup', onGesture, { capture: true }); @@ -199,7 +201,7 @@ export class OneShotAudioWeb { audioBufferManager.tryReleasingCache(this._url); this.onEnd?.(); }, this._duration * 1000); - }).catch((e) => {}); + }).catch((e) => { debug.warn('play error', e); }); } public stop (): void { @@ -257,7 +259,7 @@ export class AudioPlayerWeb implements OperationQueueable { return new Promise((resolve) => { AudioPlayerWeb.loadNative(url).then((audioBuffer) => { resolve(new AudioPlayerWeb(audioBuffer, url)); - }).catch((e) => {}); + }).catch((e) => { debug.warn('load error', url, e); }); }); } static loadNative (url: string): Promise { @@ -275,10 +277,11 @@ export class AudioPlayerWeb implements OperationQueueable { xhr.onload = (): void => { if (xhr.status === 200 || xhr.status === 0) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument audioContextAgent!.decodeAudioData(xhr.response).then((decodedAudioBuffer) => { audioBufferManager.addCache(url, decodedAudioBuffer); resolve(decodedAudioBuffer); - }).catch((e) => {}); + }).catch((e) => { debug.warn('loadNative error', url, e); }); } else { reject(new Error(`${errInfo}${xhr.status}(no response)`)); } @@ -295,6 +298,7 @@ export class AudioPlayerWeb implements OperationQueueable { AudioPlayerWeb.loadNative(url).then((audioBuffer) => { // HACK: AudioPlayer should be a friend class in OneShotAudio const oneShotAudio = new (OneShotAudioWeb as any)(audioBuffer, volume, url); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument resolve(oneShotAudio); }).catch(reject); }); @@ -313,14 +317,14 @@ export class AudioPlayerWeb implements OperationQueueable { this.pause().then(() => { this._state = AudioState.INTERRUPTED; this._eventTarget.emit(AudioEvent.INTERRUPTION_BEGIN); - }).catch((e) => {}); + }).catch((e) => { debug.warn('_onInterruptedBegin error', e); }); } } private _onInterruptedEnd (): void { if (this._state === AudioState.INTERRUPTED) { this.play().then(() => { this._eventTarget.emit(AudioEvent.INTERRUPTION_END); - }).catch((e) => {}); + }).catch((e) => { debug.warn('_onInterruptedEnd error', e); }); } } @@ -371,7 +375,7 @@ export class AudioPlayerWeb implements OperationQueueable { if (this._state === AudioState.PLAYING) { // one AudioBufferSourceNode can't start twice // need to create a new one to start from the offset - this._doPlay().then(resolve).catch((e) => {}); + this._doPlay().then(resolve).catch((e) => { debug.warn('seek error', e); }); } else { resolve(); } @@ -405,7 +409,7 @@ export class AudioPlayerWeb implements OperationQueueable { // - system automatically resume audio context when enter foreground from background. audioContextAgent!.onceRunning(this._runningCallback); // Ensure resume context. - audioContextAgent!.runContext().catch((e) => {}); + audioContextAgent!.runContext().catch((e) => { debug.warn('doPlay error', e); }); } }); } @@ -415,6 +419,7 @@ export class AudioPlayerWeb implements OperationQueueable { this._stopSourceNode(); this._sourceNode = audioContextAgent!.createBufferSource(this._audioBuffer, this.loop); this._sourceNode.connect(this._gainNode); + this._sourceNode.loop = this._loop; this._sourceNode.start(0, this._audioTimer.currentTime); this._state = AudioState.PLAYING; this._audioTimer.start(); @@ -465,6 +470,8 @@ export class AudioPlayerWeb implements OperationQueueable { stop (): Promise { this.offRunning(); if (!this._sourceNode) { + this._audioTimer.stop(); + this._state = AudioState.STOPPED; return Promise.resolve(); } this._audioTimer.stop();