Skip to content

Commit

Permalink
[Optimize] Cache current time for audio player in minigame. (#12814)
Browse files Browse the repository at this point in the history
* Cache current time for minigames

* Save current time as private member

* Make cache time changed in callback

* update cache time to abort middle state for seek
  • Loading branch information
timlyeee committed Sep 22, 2022
1 parent 72219a2 commit f341032
Showing 1 changed file with 35 additions and 11 deletions.
46 changes: 35 additions & 11 deletions pal/audio/minigame/player-minigame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export class OneShotAudioMinigame {
export class AudioPlayerMinigame implements OperationQueueable {
private _innerAudioContext: InnerAudioContext;
private _state: AudioState = AudioState.INIT;
private _cacheTime = 0;
private _needSeek = false;
private _seeking = false;

private _onPlay: () => void;
private _onPause: () => void;
Expand All @@ -55,6 +58,11 @@ export class AudioPlayerMinigame implements OperationQueueable {
private _onEnded: () => void;
private _readyToHandleOnShow = false;

private _resetSeekCache () {
this._cacheTime = 0;
this._needSeek = false;
this._seeking = false;
}
/**
* @deprecated since v3.5.0, this is an engine private interface that will be removed in the future.
*/
Expand All @@ -75,22 +83,37 @@ export class AudioPlayerMinigame implements OperationQueueable {
this._onPlay = () => {
this._state = AudioState.PLAYING;
eventTarget.emit(AudioEvent.PLAYED);
if (this._needSeek) {
this._needSeek = false;
this.seek(this._cacheTime).catch((e) => {});
}
};
innerAudioContext.onPlay(this._onPlay);
this._onPause = () => {
this._state = AudioState.PAUSED;
this._cacheTime = this._innerAudioContext.currentTime;
eventTarget.emit(AudioEvent.PAUSED);
};
innerAudioContext.onPause(this._onPause);
this._onStop = () => {
this._state = AudioState.STOPPED;
// Reset all properties
this._resetSeekCache();
eventTarget.emit(AudioEvent.STOPPED);
};
innerAudioContext.onStop(this._onStop);
this._onSeeked = () => { eventTarget.emit(AudioEvent.SEEKED); };
this._onSeeked = () => {
eventTarget.emit(AudioEvent.SEEKED);
this._seeking = false;
if (this._needSeek) {
this._needSeek = false;
this.seek(this._cacheTime).catch((e) => {});
}
};
innerAudioContext.onSeeked(this._onSeeked);
this._onEnded = () => {
this._state = AudioState.INIT;
this._resetSeekCache();
eventTarget.emit(AudioEvent.ENDED);
};
innerAudioContext.onEnded(this._onEnded);
Expand Down Expand Up @@ -204,13 +227,12 @@ export class AudioPlayerMinigame implements OperationQueueable {
get duration (): number {
// KNOWN ISSUES: duration doesn't work well
// On WeChat platform, duration is 0 at the time audio is loaded.
// On Native or Runtime platform, duration is 0 before playing.
return this._innerAudioContext.duration;
}
get currentTime (): number {
// KNOWN ISSUES: currentTime doesn't work well
// on Baidu: currentTime returns without numbers on decimal places
// on WeChat iOS: we can't reset currentTime to 0 when stop audio
if (this._state !== AudioState.PLAYING) {
return this._cacheTime;
}
return this._innerAudioContext.currentTime;
}

Expand All @@ -225,14 +247,16 @@ export class AudioPlayerMinigame implements OperationQueueable {
@enqueueOperation
seek (time: number): Promise<void> {
return new Promise((resolve) => {
time = clamp(time, 0, this.duration);
if (time === 0 && this.currentTime === 0) {
// skip invalid seek
resolve();
} else {
this._eventTarget.once(AudioEvent.SEEKED, resolve);
// KNOWN ISSUES: on Baidu: currentTime returns without numbers on decimal places
if (this._state === AudioState.PLAYING && !this._seeking) {
time = clamp(time, 0, this.duration);
this._seeking = true;
this._innerAudioContext.seek(time);
} else if (this._cacheTime !== time) { // Skip the invalid seek
this._cacheTime = time;
this._needSeek = true;
}
resolve();
});
}

Expand Down

0 comments on commit f341032

Please sign in to comment.