1+ import { TypedEventTarget } from "@/utils/TypedEventTarget" ;
12import { AudioEffectManager } from "./AudioEffectManager" ;
23import type { EngineCapabilities , IPlaybackEngine } from "./IPlaybackEngine" ;
34
@@ -19,14 +20,20 @@ export const AUDIO_EVENTS = {
1920 ERROR : "error" ,
2021 CAN_PLAY : "canplay" ,
2122 LOAD_START : "loadstart" ,
23+ SEEKED : "seeked" ,
24+ WAITING : "waiting" ,
25+ VOLUME_CHANGE : "volumechange" ,
26+ PLAYING : "playing" ,
27+ SEEKING : "seeking" ,
28+ EMPTIED : "emptied" ,
2229} as const ;
2330
2431export type AudioEventType = ( typeof AUDIO_EVENTS ) [ keyof typeof AUDIO_EVENTS ] ;
2532
2633export type AudioEventMap = {
2734 [ K in AudioEventType ] : K extends typeof AUDIO_EVENTS . ERROR
2835 ? CustomEvent < AudioErrorDetail >
29- : Event ;
36+ : CustomEvent < undefined > ;
3037} ;
3138
3239export enum AudioErrorCode {
@@ -50,7 +57,10 @@ const SEEK_FADE_TIME = 0.05;
5057 * 管理 AudioContext、音量增益、EQ连接、以及通用的淡入淡出/Seek逻辑
5158 * 实现 IPlaybackEngine 接口
5259 */
53- export abstract class BaseAudioPlayer extends EventTarget implements IPlaybackEngine {
60+ export abstract class BaseAudioPlayer
61+ extends TypedEventTarget < AudioEventMap >
62+ implements IPlaybackEngine
63+ {
5464 /** 核心上下文 */
5565 protected audioCtx : IExtendedAudioContext | null = null ;
5666 /** 主输出增益节点 (控制音量) */
@@ -183,7 +193,7 @@ export abstract class BaseAudioPlayer extends EventTarget implements IPlaybackEn
183193 const duration = options . fadeOut ? ( options . fadeDuration ?? 0.5 ) : 0 ;
184194
185195 const performPause = async ( ) => {
186- this . doPause ( ) ;
196+ await this . doPause ( ) ;
187197
188198 if ( this . audioCtx && this . audioCtx . state === "running" ) {
189199 try {
@@ -211,26 +221,36 @@ export abstract class BaseAudioPlayer extends EventTarget implements IPlaybackEn
211221 * 跳转进度
212222 * @param time 目标时间 (秒)
213223 */
214- public async seek ( time : number ) {
224+ public async seek ( time : number , immediate = false ) {
215225 this . cancelPendingPause ( ) ;
216226 // 如果已经暂停,直接跳转
217227 if ( this . paused ) {
218228 this . doSeek ( time ) ;
219229 return ;
220230 }
221- this . applyFadeTo ( 0 , SEEK_FADE_TIME ) ;
222- await new Promise ( ( resolve ) => setTimeout ( resolve , SEEK_FADE_TIME * 1000 ) ) ;
223- this . doSeek ( time ) ;
224- this . applyFadeTo ( this . volume , SEEK_FADE_TIME ) ;
231+
232+ if ( ! immediate ) {
233+ this . applyFadeTo ( 0 , SEEK_FADE_TIME ) ;
234+ await new Promise ( ( resolve ) => setTimeout ( resolve , SEEK_FADE_TIME * 1000 ) ) ;
235+ }
236+
237+ await this . doSeek ( time ) ;
238+
239+ if ( ! immediate ) {
240+ this . applyFadeTo ( this . volume , SEEK_FADE_TIME ) ;
241+ } else {
242+ this . applyFadeTo ( this . volume , 0 ) ;
243+ }
225244 }
226245
227246 /**
228247 * 停止播放并重置
229248 */
230249 public stop ( ) {
231250 this . cancelPendingPause ( ) ;
232- this . pause ( { fadeOut : false } ) ;
233- this . doSeek ( 0 ) ;
251+ // 捕获可能产生的异步错误
252+ Promise . resolve ( this . pause ( { fadeOut : false } ) ) . catch ( ( ) => { } ) ;
253+ Promise . resolve ( this . doSeek ( 0 ) ) . catch ( ( ) => { } ) ;
234254 }
235255
236256 /**
@@ -340,10 +360,10 @@ export abstract class BaseAudioPlayer extends EventTarget implements IPlaybackEn
340360 protected abstract doPlay ( ) : Promise < void > ;
341361
342362 /** 执行底层暂停 */
343- protected abstract doPause ( ) : void ;
363+ protected abstract doPause ( ) : void | Promise < void > ;
344364
345365 /** 执行底层 Seek */
346- protected abstract doSeek ( time : number ) : void ;
366+ protected abstract doSeek ( time : number ) : void | Promise < void > ;
347367
348368 /** 设置播放速率 */
349369 public abstract setRate ( value : number ) : void ;
@@ -359,47 +379,4 @@ export abstract class BaseAudioPlayer extends EventTarget implements IPlaybackEn
359379 public abstract get currentTime ( ) : number ;
360380 public abstract get paused ( ) : boolean ;
361381 public abstract getErrorCode ( ) : number ;
362-
363- /**
364- * 触发事件
365- * @param type 事件类型
366- * @param detail 事件详情
367- */
368- protected emit ( type : Exclude < AudioEventType , "error" > ) : void ;
369- protected emit ( type : typeof AUDIO_EVENTS . ERROR , detail : AudioErrorDetail ) : void ;
370- protected emit ( type : AudioEventType , detail ?: AudioErrorDetail ) : void {
371- if ( type === AUDIO_EVENTS . ERROR && detail ) {
372- this . dispatchEvent ( new CustomEvent ( type , { detail } ) ) ;
373- } else {
374- this . dispatchEvent ( new Event ( type ) ) ;
375- }
376- }
377-
378- /**
379- * 添加事件监听
380- * @param type 事件类型
381- * @param listener 事件监听器
382- * @param options 事件选项
383- */
384- public override addEventListener < K extends keyof AudioEventMap > (
385- type : K ,
386- listener : ( this : BaseAudioPlayer , ev : AudioEventMap [ K ] ) => unknown ,
387- options ?: boolean | AddEventListenerOptions ,
388- ) : void {
389- super . addEventListener ( type , listener as EventListenerOrEventListenerObject , options ) ;
390- }
391-
392- /**
393- * 移除事件监听
394- * @param type 事件类型
395- * @param listener 事件监听器
396- * @param options 事件选项
397- */
398- public override removeEventListener < K extends keyof AudioEventMap > (
399- type : K ,
400- listener : ( this : BaseAudioPlayer , ev : AudioEventMap [ K ] ) => unknown ,
401- options ?: boolean | EventListenerOptions ,
402- ) : void {
403- super . removeEventListener ( type , listener as EventListenerOrEventListenerObject , options ) ;
404- }
405382}
0 commit comments