Skip to content

Commit 5854f44

Browse files
committed
🐞 fix: 修复FFmpeg竞态条件
1 parent 80c97a7 commit 5854f44

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

src/core/audio-player/ffmpeg-engine/FFmpegAudioPlayer.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export class FFmpegAudioPlayer extends BaseAudioPlayer {
5757

5858
/** 当前音频源地址 */
5959
private _src: string = "";
60+
/** 用于取消正在进行的 fetch 请求 */
61+
private abortController: AbortController | null = null;
6062

6163
constructor() {
6264
super();
@@ -125,6 +127,13 @@ export class FFmpegAudioPlayer extends BaseAudioPlayer {
125127
this.playerState = "loading";
126128
this.emit(AUDIO_EVENTS.LOAD_START);
127129

130+
// 唯一的加载 ID
131+
const loadId = ++FFmpegAudioPlayer.messageIdCounter;
132+
this.currentMessageId = loadId;
133+
134+
// 取消 fetch
135+
this.abortController = new AbortController();
136+
128137
return new Promise<void>((resolve, reject) => {
129138
this.metadataResolve = resolve;
130139
this.metadataReject = reject;
@@ -135,15 +144,19 @@ export class FFmpegAudioPlayer extends BaseAudioPlayer {
135144
this.init();
136145
}
137146

138-
const response = await fetch(url);
147+
const response = await fetch(url, { signal: this.abortController?.signal });
148+
// 检查是否被新的 load 调用覆盖
149+
if (this.currentMessageId !== loadId) return;
139150
if (!response.ok) throw new Error(`Failed to fetch ${url}`);
140151
const blob = await response.blob();
152+
// 再次检查
153+
if (this.currentMessageId !== loadId) return;
154+
141155
const file = new File([blob], "und", { type: blob.type });
142156

143157
this.worker = new AudioWorker();
144158
this.setupWorkerListeners();
145159

146-
this.currentMessageId = ++FFmpegAudioPlayer.messageIdCounter;
147160
if (this.worker) {
148161
this.worker.postMessage({
149162
type: "INIT",
@@ -153,6 +166,8 @@ export class FFmpegAudioPlayer extends BaseAudioPlayer {
153166
});
154167
}
155168
} catch (e) {
169+
// 被新的 load 取消了,不需要处理
170+
if ((e as Error).name === "AbortError") return;
156171
this.cleanupLoadPromise();
157172
this.handleError((e as Error).message, AudioErrorCode.NETWORK);
158173
reject(e);
@@ -283,6 +298,13 @@ export class FFmpegAudioPlayer extends BaseAudioPlayer {
283298
*/
284299
private reset() {
285300
this._errorCode = 0;
301+
302+
// 取消正在进行的 fetch 请求
303+
if (this.abortController) {
304+
this.abortController.abort();
305+
this.abortController = null;
306+
}
307+
286308
if (this.metadataReject) {
287309
this.metadataReject(new Error("Aborted by reset"));
288310
this.cleanupLoadPromise();

0 commit comments

Comments
 (0)