File size: 2,696 Bytes
2498190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
class AudioQueueManager {
    private queue: string[] = [];
    private isPlaying: boolean = false;
    private currentAudio: HTMLAudioElement | null = null;
    private _instance: AudioQueueManager | null = null;
  
    constructor() {}
  
    public static getInstance(): AudioQueueManager {
      if (!(window as any).audioQueueInstance) {
        (window as any).audioQueueInstance = new AudioQueueManager();
      }
      return (window as any).audioQueueInstance;
    }
  
    public play(path: string) {
      // Avoid adding duplicates if the same sound is already at the end of the queue
      // This helps with the "double trigger" issue if the UI sends it twice rapidly
      if (this.queue.length > 0 && this.queue[this.queue.length - 1] === path) {
          return;
      }
      // Also check if currently playing is the same sound and we are just starting (optional robustness)
      
      console.log(`[AudioQueue] Added to queue: ${path}`);
      this.queue.push(path);
      this.processQueue();
    }
  
    private processQueue() {
      if (this.isPlaying || this.queue.length === 0) {
        return;
      }
  
      const nextPath = this.queue.shift();
      if (!nextPath) return;
  
      this.isPlaying = true;
      
      // Prefix with /audio/ if not present and it's a relative filename
      const fullPath = nextPath.startsWith('/') || nextPath.startsWith('http') 
          ? nextPath 
          : `/audio/${nextPath}`;
  
      this.currentAudio = new Audio(fullPath);
      
      this.currentAudio.onended = () => {
        console.log(`[AudioQueue] Finished: ${nextPath}`);
        this.isPlaying = false;
        this.currentAudio = null;
        this.processQueue(); // Play next
      };
  
      this.currentAudio.onerror = (e) => {
        console.error(`[AudioQueue] Error playing ${nextPath}`, e);
        this.isPlaying = false;
        this.currentAudio = null;
        this.processQueue(); // Skip and play next
      };
  
      this.currentAudio.play().catch(e => {
          console.error(`[AudioQueue] Autoplay failed for ${nextPath}`, e);
          this.isPlaying = false;
          this.processQueue();
      });
    }
  
    public stopAll() {
      if (this.currentAudio) {
        this.currentAudio.pause();
        this.currentAudio = null;
      }
      this.queue = [];
      this.isPlaying = false;
    }
  }
  
  export const AudioQueue = {
    play: (path: string) => {
        if (typeof window !== 'undefined') {
            AudioQueueManager.getInstance().play(path);
        }
    },
    stopAll: () => {
        if (typeof window !== 'undefined') {
            AudioQueueManager.getInstance().stopAll();
        }
    }
  };